1

I use the following code to validate income numbers from ajax calls:

    public Tuple<bool, int> ValidateInt(string TheCandidateInt)
    {
        int TheInt = 0;

        if (Int32.TryParse(TheCandidateInt, out TheInt))
        {
            return new Tuple<bool, int>(true, TheInt);
        }
        else
        {
            return new Tuple<bool, int>(false, 0);
        }
    }

    public Tuple<bool, short> ValidateShort(string TheCandidateShort)
    {
        short TheShort = 0;

        if (Int16.TryParse(TheCandidateShort, out TheShort))
        {
            return new Tuple<bool, short>(true, TheShort);
        }
        else
        {
            return new Tuple<bool, short>(false, 0);
        }
    }

I also have the same types of function for Byte and Short. As you can see, I pass in a string and the return is a Tuple where Item1 is a boolean and Item2 is the value.

Is there a way to change these 4 methods into 1 and somehow factor out the data type of the parsing?

Thanks.

frenchie
  • 51,731
  • 109
  • 304
  • 510
  • 6
    Is there some reason you're using a tuple of bool and int instead of a `Nullable`? A nullable int already is a tuple of bool and int. I would write your method `public int? ValidateInt(string s) { int j; return int.TryParse(s, out j) ? (int?) j : (int?) null; }` – Eric Lippert Dec 22 '13 at 17:29
  • 1
    Have a look at [this question](http://stackoverflow.com/questions/2961656/generic-tryparse) – Artyom Neustroev Dec 22 '13 at 17:31
  • I see no possibility. There would have to be a base type common to all your concrete types that declares the `TryParse()` method. – Thomas Weller Dec 22 '13 at 17:31
  • 1
    Aside from anything else, each of your methods can be a lot shorter: `int result; return Tuple.Create(int.TryParse(input, out result), result);` (But I'd use Eric's version too, of course...) – Jon Skeet Dec 22 '13 at 17:34
  • @EricLippert: Your answer would shorten the code of each method but I'm looking to combine all these methods into one. What do you think of Yuriy's answer? – frenchie Dec 23 '13 at 16:41
  • My advice: don't combine things that do different things. If there are four types you can validate then make four methods. This is cheap, trivial code. Don't spend a lot of time trying to make it general. Your time is valuable, and you've probably wasted more time trying to make it general than the generality saves you. – Eric Lippert Dec 23 '13 at 17:40
  • @EricLippert: Ok, I'll take your suggestion to keep it simple. I've also run into situations where it seemed possible to factor out some code only to find out that there are too many different cases that end up turning into lots of parameters for the factoring to work. BTW, your new picture is better but IMO it also makes you look less reflective . – frenchie Dec 23 '13 at 18:24

2 Answers2

2

You can merge your methods into one using generics:

public static Tuple<bool, T> ValidateValue<T>(string input) where T : struct
{
    T result = default(T);
    try
    {
        result = (T)TypeDescriptor.GetConverter(typeof(T)).ConvertFromString(input);
    }
    catch
    {
        return new Tuple<bool, T>(false, result);
    }
    return new Tuple<bool, T>(true, result);
}

As to factoring out the data type of parsing, you will still have to specify it as generic parameter.

ValidateValue<byte>("255");
Yurii
  • 4,811
  • 7
  • 32
  • 41
  • Thanks for the answer, that's really cool! What does "where T : struct" mean? – frenchie Dec 23 '13 at 00:28
  • @frenchie, it's [type parameter constraint](http://msdn.microsoft.com/en-us/library/d5x73970.aspx) which means that generic parameter `T` is limited to [value types](http://msdn.microsoft.com/en-us/library/s1ax56ch.aspx). – Yurii Dec 23 '13 at 07:28
0

You can create a delegate that encapsulates the TryParse call and by that create a more general version of your validation methods. The following sample shows the outline:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestTryParseDelegate
{
    class Program
    {
        private delegate bool TryParseDelegate<T>(string candidate, out T result)
            where T : struct;

        private static Tuple<bool, T> Validate<T>(string candidate, TryParseDelegate<T> tryParseDel)
            where T : struct
        {
            T result;
            return Tuple.Create(tryParseDel(candidate, out result), result);
        }

        public static Tuple<bool, int> ValidateInt(string TheCandidateInt)
        {
            return Validate<int>(TheCandidateInt, int.TryParse);
        }

        public static void Main()
        {
            var result = ValidateInt("123");
            Console.WriteLine(result);
        }
    }
}

I'd still suggest to encapsulate the general version in specialized methods as in your sample as the delegate is a implementation detail that you might not want to publish.

Markus
  • 20,838
  • 4
  • 31
  • 55
  • Upvoted, but can be improved. Body of `Validate` method can be written `T result; return Tuple.Create(tryParseDel(candidate, out result), result);`. Also body of `ValidateInt` should allow simplification to `return Validate(TheCandidateInt, int.TryParse);`. – Jeppe Stig Nielsen Dec 22 '13 at 20:06