views:

993

answers:

4

I currently use this handy conversion extension method to do conversions between types:

    public static T To<T>(this IConvertible obj)
    {
        return (T)Convert.ChangeType(obj, typeof(T));
    }

However, it doesn't like converting valid values to Nullable, for example, this fails:

    "1".To<int?>();

Obviously, 1 is easily converted to an (int?), but it gets the error:

    Invalid cast from 'System.String' to 'System.Nullable`1[[System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]'.

This is an obviously simplified example, in reality I'm using it to do conversions from string types like so:

packageDb.Quantity = package.package.ElementDeep(Namespace + "PackageQuantity", Namespace + "ActualQuantity", Namespace + "Quantity").ValueOrNull().To<int?>();

If Convert.ChangeType doesn't like Nullable, anyone have any great ideas?

+1  A: 

Maybe I'm missing the point, but in the instance of Nullable, how does your method provide either a readability, performance, or maintenance advantage over a simple cast, like (int?)1 ?

Aside from that, perhaps another extension method?

public static T? ToNullable<T>(this T obj) where T:struct
{
    return (T?)obj;
}

Edit

After reviewing your edit, why would the generic function that I provided not work as a substitute to your To<T> function in that line of code? You can't allow a conversion to Nullable for any type (which is why ChangeType doesn't work) because that generic only accepts value types. You'll either have to use a function like the one I provided or change your signature of To<T> to only accept value types and add a special case for Nullable<T>.

Adam Robinson
Is there a way to roll this into my existing method, and have it detect the nullable generic, and handle appropriately?
TheSoftwareJedi
Adam Robinson
+1  A: 

This is the method that I currently use (I got my answer on SO), it converts from string to nullable type:

    public static Nullable<T> ConvertToNullable<T>(this string s) where T : struct
    {
        if (!string.IsNullOrEmpty(s.Trim()))
        {
            TypeConverter conv = TypeDescriptor.GetConverter(typeof(Nullable<>).MakeGenericType(typeof(T)));
            return (Nullable<T>)conv.ConvertFrom(s);
        }
        return null;
    }
Nathan Koop
+2  A: 
public static T To<T>(this IConvertible obj) 
{
    Type t = typeof(T);
    if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>))
     t = t.GetGenericArguments()[0];

    return (T)Convert.ChangeType(obj, t); 
}

But if the conversion fail, it will throw an exception, not returning a null as should be expected.

Henrique
good answer, perfectly on track, but I can only award correct to 1, and Luke's does the null checking. Cheers!
TheSoftwareJedi
+15  A: 
public static T To<T>(this IConvertible obj)
{
    Type t = typeof(T);
    Type u = Nullable.GetUnderlyingType(t);

    if (u != null)
    {
        if (obj == null)
            return default(T);

        return (T)Convert.ChangeType(obj, u);
    }
    else
    {
        return (T)Convert.ChangeType(obj, t);
    }
}
LukeH
Thanks Luke! This is perfect. It was t.GetGenericTypeDefinition() == typeof(Nullable<>)) and Nullable.GetUnderlyingType(t) that really helped me out here. This is good stuff. Thanks again.
TheSoftwareJedi