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.

Thursday, October 05, 2006

:: Operator

The namespace alias qualifier operator.

I ran across this operator for the first time the other day in a c# application (an XNA app, pretty cool stuff :) ). Anyhow, it looked like some c / objective c code at first to me. I'd never seen this used in c# before.

Basically here's what it does, with a not so elegant example:

(Here's a class that belongs to an ungodly deep namespace)

namespace some.really.big.nested.namespac {

public SomeClass {

public enum Number {

small,

medium,

large

}

}

}

(Here's a class that needs to use the above class, but this class also has a method with the same name as the above class name)

namespace smallNamespace {

class SomeOtherClass {

public void Number(int size) {

if((int)some.really.big.nested.namespace.Number.small == size)

// do something

}

}

}

Now that is pretty ugly stuff..

In a large project you may end up with a situation where a class name in one namespace is used in another namespace as a field, method etc. In which case you would have to use the fully qualified name to let the compiler know which 'thing' your talking about.

Now here is a better way to do this, it shrinks down your code, and is easy to understand:

namespace smallNamespace {

using bigNameSpace = some.really.big.nested.namespac;

class SomeOtherClass {

public void Number(int size) {

if((int)bigNameSpace::Number.small == size)

// do something

}

}

}

Create a namespace alias with the using statement.

the '::' is placed between the two identifiers, and invokes a different lookup for the item.

Another common use of this variable is for the global namespace

"global::Console.WriteLint("Hello World");"

Friday, September 22, 2006