Convert to unknown generic type: ChangeType<T>

by Alex Siepman 6. March 2012 21:15

Problem

When you create a generic method (Foo<T>) or generic class (Bar<T>), it often happens that you need to change (or convert) a type to T. In these situations you need a ChangeType<T> function that changes "any" type to T. Unfortunately this is not a standard method. The Cast() method of Linq looks like a solution but it is very limited. This wil not work for a lot of types:

public static T ChangeTypeLinqVariant<T>(this object value)
{
    return (new [] {value}).Cast<T>().Single();
}

Examples

Most obvious examples where you need a ChangeType<T> method are:

  • Method returns T but the parameter of the method is an object, string, XML or data from a DataReader.
  • Method returns T1 but the parameters of the method is T2 (T1 Foo<T1, T2>(T2 value))

A less obvious example is:

private void AddItem<TK, TV>(ref Dictionary<TK, TV> dictionary, TK key, TV value)
{
    if (key is string)
    {
        // This wil not compile because key is a TK, not a string
        key = key.ToString().ToLower();
        // This will do the job
        key = key.ToString().ToLower().ChangeType<TK>();
    }
    if (dictionary.ContainsKey(key)) return;
    dictionary.Add(key, value);
}

Solution

A start it the good direction was a post on StackOverflow. But that solution didn't work for types like enum's, strings, Guids, etc. So I add soms new code to it and now it works for most of the common scenarios.

public static T ChangeType<T>(this object value, CultureInfo cultureInfo)
{
    var toType = typeof(T);

    if (value == null) return default(T);

    if (value is string) 
    {
        if (toType == typeof(Guid)) 
        {
            return ChangeType<T>(new Guid(Convert.ToString(value, cultureInfo)), cultureInfo); 
        }
        if ((string)value == string.Empty && toType != typeof(string)) 
        {
            return ChangeType<T>(null, cultureInfo);
        }
    }
    else
    {
        if (typeof(T) == typeof(string)) 
        {
            return ChangeType<T>(Convert.ToString(value, cultureInfo), cultureInfo);
        }
    }

    if (toType.IsGenericType &&
        toType.GetGenericTypeDefinition() == typeof(Nullable<>))
    {
        toType = Nullable.GetUnderlyingType(toType); ;
    }

    bool canConvert = toType is IConvertible || (toType.IsValueType && !toType.IsEnum);
    if (canConvert)
    {
        return (T)Convert.ChangeType(value, toType, cultureInfo);
    }
    return (T)value;
}

It might be handy to add some extra overloads like:

public static T ChangeType<T>(this object value)
{
    return ChangeType<T>(value, CultureInfo.CurrentCulture);
}

Tags:

Generics

Pingbacks and trackbacks (1)+

Add comment

  Country flag

biuquote
  • Comment
  • Preview
Loading

About the author

I am a software architect at Roxit and also a C# Developer. My main interests in the area of ​​C# are LINQ and generics

Visit my personal homepage (Dutch) for more info about me.

Month List

Page List