views:

1310

answers:

4

I am working on a tool where I need to convert string values to their proper object types. E.g. convert a string like 2008-11-20T16:33:21Z to a DateTime value. Numeric values like 42 and 42.42 must be converted to an Int32 value and a Double value respectively.

What is the best and most efficient approach to detect if a string is an Integer or a Number? Is Int32.TryParse or Double.TryParse the way to go?

+6  A: 

In terms of efficiency, yes, TryParse is generally the preferred route.

If you can know (for example, by reflection) the target type in advance - but don't want to have to use a big switch block, you might be interested in using TypeConverter - for example:

        DateTime foo = new DateTime(2008, 11, 20);
        TypeConverter converter = TypeDescriptor.GetConverter(foo);
        string s = converter.ConvertToInvariantString(foo);
        object val = converter.ConvertFromInvariantString(s);
Marc Gravell
+15  A: 

Int.TryParse and Double.TryParse have the benefit of actually returning the number.

Something like Regex.IsMatch("^\d+$") has the drawback that you still have to parse the string again to get the value out.

David Kemp
The other added benefit is that the TryParse method returns a boolean variable, so it is easy to code for your success and fail scenarios when parsing the number.
Dillie-O
+2  A: 

I would recommend the .TryParse() personally. That's what I use anyhow. That's if your data is going to be wrong now and again. If you're certain the incoming strings will be able to convert to integers or doubles without a hitch, the .Parse() is faster.

Here's an interesting link to support this.

Mat Nadrofsky
A: 

Keeping the idea of a converter to skip a switch block, you could use the concept of Duck Typing. Basically, you want to turn a string to X, so you make a method that will call X.TryParse(string, out X x) if X has TryParse on it, otherwise you just don't bother (Or I suppose you could throw an error). How would you do this? Reflection and Generics.

Basically you would have a method that would take in a type and use reflection to see if it has TryParse on it. If you find such a method you then call it and return whatever TryParse managed to get. This works well with just about any value type like say Decimal or DateTime.

public static class ConvertFromString
{
  public static T? ConvertTo<T>(this String numberToConvert) where T : struct
  {
    T? returnValue = null;

    MethodInfo neededInfo = GetCorrectMethodInfo(typeof(T));
    if (neededInfo != null && !numberToConvert.IsNullOrEmpty())
    {
      T output = default(T);
      object[] paramsArray = new object[2] { numberToConvert, output };
      returnValue = new T();

      object returnedValue = neededInfo.Invoke(returnValue.Value, paramsArray);

      if (returnedValue is Boolean && (Boolean)returnedValue)
      {
        returnValue = (T)paramsArray[1];
      }
      else
      {
        returnValue = null;
      }    
    }

    return returnValue;
  }
}

Where GetCorrectMethodInfo would look something like this:

private static MethodInfo GetCorrectMethodInfo(Type typeToCheck)
{

  MethodInfo returnValue = someCache.Get(typeToCheck.FullName);

  if(returnValue == null)
  {
    Type[] paramTypes = new Type[2] { typeof(string), typeToCheck.MakeByRefType() };
    returnValue = typeToCheck.GetMethod("TryParse", paramTypes);
    if (returnValue != null)
    {
      CurrentCache.Add(typeToCheck.FullName, returnValue);
    }
  }

  return returnValue;
}

And use would be:

decimal? converted = someString.ConvertTo<decimal>();

I hate plugging myself, but I have this fully explained here:

GetCorrectMethodInfo

Rest of It

Programmin Tool