Monday, October 23, 2006

Setting a Nullable Enum Through Reflection

A colleague and I had recently put together an ORM mapper that uses reflection to set all of our objects dynamically within our application. Things were going great, and it was doing everything we asked of it. It worked with mulitple databases, was much quicker, and easier to use, than some of the other popular ORMs out there.

That was until we ran into a hickup with Nullable Enumerations. With nullable ints, DateTimes etc. it's easy because c# auto box's these for you. But with custom Enum types it can't really do the boxing for you as they're custom types. So with this Enumeration

public enum Status {
    Open,
    Closed,
    Pending,
    Waiting
}

And this property

public Status? Status;

You could set the property this way

Type type = t.GetType();
PropertyInfo pi = type.GetProperty("Status",
BindingFlags.Public |
BindingFlags.IgnoreCase |
BindingFlags.Instance);
pi.SetValue(t, (Status?)2, null);

But you HAVE to know the type at this point to do this casting. With our ORM tool we use one class that sets ALL of our objects. Some of these may have a nullable Enums, and most will not. So we will never know the type. So... to get around this here is what we ended up doing. (After much searching on the net without any solutions)

Type propType = pi.PropertyType;
if (propType.IsGenericType &&
propType.GetGenericTypeDefinition()==
typeof(Nullable<>)) {
Type[] typeCol = propType.GetGenericArguments();
Type nullableType;
if (typeCol.Length > 0) {
nullableType = typeCol[0];
if (nullableType.BaseType == typeof(Enum)) {
object o = Enum.Parse(nullableType, "2");
pi.SetValue(t, o, null);
}
}
}

We first check that the PropertyType is a Generic and that it is a Nullable<> type. Next we generate an array of Types, and then we get the first item in that collection (Which will be the Custom Enumeration type).


Next we check that the baseType is a type of Enumeration (Just another check). Then we make a new object, because we don't know the type, using the Enum.Parse where we pass in the Type and the value, which could be an int.toString or whatever. Then finally we use the PropertyInfo.SetValue method where the first 2 params are objects. Since everything is set and we have the custom type of the nullable enum we can now set this property of our object dynamically at run time.

5 comments:

Anonymous said...

Thanks - just what I was looking for.

Chris

Anonymous said...

Thanks guys, looking for a solution for the same problem and here it is! Saved me a lot of head scratching. :)

Clayton Gulick said...

thanks, helped me solve the exact same problem

Anonymous said...

THANK YOU!!!! <3

Anonymous said...

good..