Friday, 11 September 2015

A much better String to ValueType converter implementation in Csharp

There are situations when one needs to convert the string values to ValueTypes(int, guid, datetime, Enums, Nullables etc.). A situation of doing these conversion could be to read Settings store in Configuration file or in database and converting them to their respective value type.
I have seen people have writing if..else ladder to match the type and use the specific TypeConverter method from static class i.e. Convert.To<ValueType>();

Here’s a sample what was observed:

public object ConvertToValueType(string value, Type targetType)
{
    object result = null;
 
    bool isEmpty = string.IsNullOrWhiteSpace(value);
 
    if (targetType == typeof (string))
    {
        result = value;
    }
    else if (targetType == typeof (Int32) || targetType == typeof (int))
    {
        if (isEmpty)
        {
            result = 0;
        }
        else
        {
            result = Int32.Parse(value);
        }
    }
    else if (targetType == typeof (Guid))
    {
        if (isEmpty)
        {
            result = Guid.Empty;
        }
        else
        {
            result = new Guid(value);
        }
    }
    else if (targetType.IsEnum)
    {
        result = Enum.Parse(targetType, value);
    }
    else if (targetType == typeof (byte[]))
    {
        result = Convert.FromBase64String(value);
    }
    else if (targetType == typeof (DateTime))
    {
        if (isEmpty)
        {
            result = DateTime.MinValue;
        }
        else
        {
            result = Convert.ToDateTime(value);
        }
    }
 
    return result;
}

This solution would work and I can tell half of you have seen or done things like this. But look at this again. There will be an IF…Else condition for each type in the system.
The problem can be solved by using a System class System.ComponentModel.TypeDescriptor. Which provide underlying information of a Type. So the above complex statement chain for Conversion can be converted to something like this using an extension method accepting generic types:


private static bool TryConvertTo<T>(this string value, out object result)
        {
            var newType = typeof(T);
result = default(T);
            if (string.IsNullOrWhiteSpace(value))
            {
        // simply return. A default value is already provided to out parameter.
                return true;
            }
 
            try
            {
                var converter = TypeDescriptor.GetConverter(typeof(T));
                result = (T)converter.ConvertFromString(value);
                return true;
            }
            Catch(Exception exception) 
            {
          // Log this exception if required. 
               // throw new InvalidCastException(string.Format("Unable to cast the {0} to type {1}", value, newType, exception));
        return false;
            }
        }

I have created this method with “Try-Parse” pattern so that it doesn’t break the application but simply returns ture/false if conversion is successful or failed due to exception or any other reasons. I found this classes in one the solution of Asp.net. You can find the complete class create for this blog post here.
Thumb Rule: Before you decide to jump into changing the business logic, try writing some tests for complete coverage of existing converter and then apply the changes and see if it’s not breaking any previously running cases.
I have wrote couple of tests to see if it works. You can find those tests for string to Converter here. These are not complete tests to validate every conversion so use and test it by your own.