Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is using successive TryParse calls a sound way to guess a string's 'real type'?

Tags:

c#

.net

This relates to my Are there any project templates for using T4 to generate classes? question. I have lists of string (nvarchar) parameter values I need to generate properly typed class properties for.

The values are all primitives - the most complex being DateTime - in the set { int, double, bool, DateTime }. Currently I have hand coded typed properties for one - of many - such lists, and to parse the string I start with DateTime.TryParseExact. If that fails, I try Double.TryParse, and at the bottom I give up guessing and assume it really is a string.

Is this a fairly sound approach, or are there other more complicated or accurate methods I should rather use?

like image 290
ProfK Avatar asked Aug 21 '13 14:08

ProfK


People also ask

What is the TryParse method?

TryParse(String, Int32) Converts the string representation of a number to its 32-bit signed integer equivalent. A return value indicates whether the conversion succeeded.

What method parameter type is used by TryParse method?

The type of this parameter is System.

What does enum TryParse do?

TryParse(Type, String, Boolean, Object)Converts the string representation of the name or numeric value of one or more enumerated constants to an equivalent enumerated object.

Can you TryParse a string?

TryParse(String, NumberStyles, IFormatProvider, Single) Converts the string representation of a number in a specified style and culture-specific format to its single-precision floating-point number equivalent. A return value indicates whether the conversion succeeded or failed.


2 Answers

If the set of values was only [double, DateTime, bool] this would be an exhaustive but fairly sound method. There is simply so overlap between those sets (true is always a bool and 5 is never a bool).

Having both int and double makes this proposition a bit flaky because there is a large amount of overlap. Essentially any int can be also seen as a double. How am I to interpret for example 4 if it appears in the value set? It could be interpreted both ways and if values change over time you could see the type of your generated code changing as well.

Consider if a column always had whole numbers simply by coincidence. Hence you generated int value and wrote a bit of code that depended on them being int. Then a month or so later a non-whole number was added and suddenly you are spitting out double values. This would probably have a non-trivial affect on your code.

Personally the approach I would take is to simply have another table which dictated the type of the contents.

like image 157
JaredPar Avatar answered Oct 11 '22 11:10

JaredPar


Have a look at Convert.ChangeType and TypeDescriptor.GetConverter.

I've written an extension method to do this for me:

public static T Convert<T>(this object obj)
{
  T result;
  try
  {
    result = (T)System.Convert.ChangeType(obj, typeof(T));

    if (object.ReferenceEquals(result, null))
    {
      var typeConverter = !obj.IsNullable()
        ? TypeDescriptor.GetConverter(typeof(T))
        : new NullableConverter(typeof(T));

      result = obj is string
        ? (T)typeConverter.ConvertFromString(obj as string)
        : (T)typeConverter.ConvertTo(obj, typeof(T));
    }
  }
  catch (Exception)
  {
    result = default(T);
  }

  return result;
}

public static bool IsNullable<T>(this T obj)
{
  return Nullable.GetUnderlyingType(typeof(T)) != null;
}

Usage:

var itemsToConvert = new[] { "4", "5.98", "false", DateTime.Now.ToString() };
var @int = itemsToConvert[0].Convert<int>();
var @double = itemsToConvert[1].Convert<double>();
var @bool = itemsToConvert[2].Convert<bool>();
var @dateTime = itemsToConvert[3].Convert<DateTime>();

Console.WriteLine(@"int: {0}, Type: {1}", @int, @int.GetType());
Console.WriteLine(@"double: {0}, Type: {1}", @double, @double.GetType());
Console.WriteLine(@"bool: {0}, Type: {1}", @bool, @bool.GetType());
Console.WriteLine(@"DateTime: {0}, Type: {1}", @dateTime, @dateTime.GetType());

Output:

int: 4, Type: System.Int32
double: 5.98, Type: System.Double
bool: False, Type: System.Boolean
DateTime: 2013/08/21 06:01:07 PM, Type: System.DateTime

Hope this helps.

like image 45
Sameer Singh Avatar answered Oct 11 '22 10:10

Sameer Singh