Posts Tagged ‘generics’

Where did my type go?

Saturday, November 3rd, 2007

With the .Net 2.0 release in 2005 it was finally possible to use generics in c#. That dramatically reduced the code complexity and made programming in that language a little bit nicer again. The classes stayed flexible and elegant and despite the generics support was not even close to the magic it has in other languages it was better than nothing. I started using it immediately.

“wow… generics are so cool!”

A few weeks ago I wanted to provide my generic class, lets call it HandlePool<>, in a remoting application. The first problem I run into was that there is no way to access generics when the inner type is unknown.

HandlePool{} h = remotedObject.GetHandlePool();

wont work. Also

HandlePool{Object} h = remotedObject.GetHandlePool();

will fail on runtime while casting the object because of the underlying and fundamental problem that e.g. List<String> may not be casted into a List<Object>. Generics used in a context where you don’t know the types explicitly will cause huge problems because you cannot refer to a “generic base type”. The only possible way is accessing it over an interface (which must not be generic, otherwise the problem starts again).

“Well, generics has it’s drawbacks”

Because the generic class does just provide a handful operations I decided to wrap it by copying its interface to a normal object so I could access it with:

remotedObject.HandlePool.GetHandleByName();

However, when accessing the remoted object like that, the client receives a TypeLoadException.
Soon I noticed that the exception occurred while deserializing the remoted object. After stumbling around a bit, I discovered that during the object’s deserialization the client’s app domain found the type HandlePool<LoggingHandle> in the deserialization context but could not resolve the type because it was not defined in the app domain yet of course. How could it be?

By writing HandlePool<LoggingHandle> in my servers object I defined the new type HandlePool<LoggingHandle> on the fly in my server’s AppDomain. That was unknown to the clients because until then nobody defined that type there. However, I can’t do it in my client anyway because I don’t know yet which types I will receive from the server in future.

“Argh!”

As always in those “Damn! I’m fucked and have to rewrite everything” situations, I glanced at the reflection API. Until that day it always provided a solution for last-minute-design hacks.
So I hoped to be able to invoke the type somehow by generics and avoid the TypeLoadException

The old reflection API provided this way:

Type t; 
 
//this implicitly requires an empty constructor 
 
Object o = t.GetConstructor(
       new Type[]{} ).Invoke( new Object[]{} );

“Nice”

I tried but it still didn’t work. TypeLoadException… mhh…

Haide, it’s .Net, hacks are allowed and everywhere. So I continued trying…

After that I came up with the idea: building the type HandlePool<LoggingHandle> during runtime by reflection. Checking the reflection API.. and..
uh.. No way to specify a generic type. This was the first time I realized that maybe generics is not that nice if used across several modules and its unknown with which specific type you have to deal with.
But after a few minutes I found the MakeGenericType command. From msdn:

Substitutes the elements of an array of types for the type parameters of the current generic type definition and returns a Type object representing the resulting constructed type.

“Wohooo!”

So I need the type information of the type “inside” the generic and I will be able to add the correct type definition into my AppDomain which allows me to deserialize the remoted generic object.

“So how to get that type now?”

If I do something like remotedObject.HandlePool.GetGenericType(), I wont come very far because HandlePool has to be resolved first and that will result in an exception.

Thus I need a helper object with which I somehow can get the type by do something like

helper.GetGenericType()

And then I have the “inside” type in my app domain. The assembly where this type is defined is has to be around as well, but I ignore that now.

So when I have the generic type in my app domain, I can do something like

Type innerType = helper.GetGenericType(); 
 
//building generic type
Type newConcreteGenericType = Type.MakeGenericType(
       new Type[]{ innerType } ); 
 
//now deserialization works
remotedObject.GetHandlePool();

And it worked!

“Uhuu, reflection saved me another time”

Of course compared to static generic definitions this is incredible slow, but I used it just once in an init method and thus for me it was okay. (Note: I skipped the exception handling)

Wasn’t that easy. I will pay attention when using generics the next time. Sometimes they cause more problems than they actually solve.