Kyle Sletten

Nullable Conversion

25 Jun 2015

.NET has a static class called System.Convert which allows you to dynamically
change the type of an object. The only problem with the API is that it takes
and returns an object which you have to cast, so I tried to write a method that
would convert one type to another using reflection.

The code is simple enough and it allows for some relatively easy conversions
from one type to another, but I ran into a big problem when using it. C# has
Nullable types which allow you to represent a possibly null integer for
instance.

varfive=(int?)5;varnothing=(int?)null;

It seemed simple enough to use them, but when I tried the following, it failed
spectacularly with an InvalidCastException:

varthree=ChangeType<int?>(3);

Apparently I am not able to cast from Int32 to Nullable<Int32>, but I had
just done it a couple of lines before, so I decided to dig deeper to figure out
what exactly had not worked. I fired up LINQPad and used the IL view to compare
the code of ChangeType to what I had seen with the earlier cast to int?.

When I saw this I realized that when we're casting to a nullable type, we're
not doing a regular cast operation, it's a cast operator added for convenience.
To emulate this cast in my method, I need a new version of ChangeType that
detects a conversion to a nullable type and constructs a new nullable instance
in that case. To do that, I have to use reflection to get the constructor for
the nullable type and call it.

publicstaticobjectChangeTypeEx(objectobj,Typetype){if(type.IsGenericType&&type.GetGenericTypeDefinition()==typeof(Nullable<>)){// get the T in ?TvartypeArgument=type.GetGenericArguments()[0];obj=System.Convert.ChangeType(obj,typeArgument);// get the Nullable<T>(T) constructorvarctor=(T)type.GetConstructor(new[]{typeArgument});returnctor.Invoke(new[]{obj});}returnSystem.Convert.ChangeType(obj,type);}

While this code is certainly a niche use-case and one may argue that inserting
the cast yourself would be better, it allows for innovation in dynamically
typed scenarios like loading nullable data from an IDataReader.

// get the id column with a default of 0 if id is NULLvarid=reader.GetNullableFieldValue<int>("id",0);// get the quantity but fall back to (int?)null if it's NULLvarquantity=reader.GetNullableFieldValue<int?>("quantity");// it even works with object typesvarname=reader.GetNullableFieldValue<string>("name","UNNAMED");