2009-05-30

Generics instantiation using MEF

This post will discuss techniques of instantiating generics types at runtime.

You can download the code sample here.

Generics has lots of benefits (which is not the subject of this post).
In order to gain most of the generics benefits you should instantiate the generics at design time whenever it possible.
But using generics long enough you come across needs of instantiate the generics at runtime (mostly because there is scenarios when you don’t know the exact type of T at design time.

How can you instantiate generics at runtime?

you can instantiate it at runtime using reflection, as the following code demonstrate (but it is very expensive instantiation technique):

public class MyGenericType<T> {
public MyGenericType ( T instance ) {
this.Instance = instance;
}
public T Instance { get; set; }
public static object Create ( object body ) {
Type gnType = typeof (MyGenericType<>);
Type[] typeArgs = { body.GetType () };
Type genericType = gnType.MakeGenericType (typeArgs);
object o = Activator.CreateInstance (
genericType, body);
return o ;
}
}

The above code has simple generics class with static Create method which use reflection in order to instantiate the class

How can we improve it?

We can use the factory or DI (dependency injection).
Factory code will look something like the following code:

public static object Create ( object body ) {
if (body is string)
return new MyGenericType<string> (body as string);
if (body is DataTable)
return new MyGenericType<DataTable> (body as DataTable);
throw new NotImplementedException()
}

The problem is this, writing hardcoded factory case extensibility problem which require recompilation whenever new type should added and cross reference conflict in-case that the new type locate in dll that already reference our assembly.
So obviously you can use DI to solve the problem (which is good acceptable solution)

Taking it one step further

I choose different approach which is using the newly MEF technology for addressing this problem by Exporting the factories as MEF export parts.
The following code assume that you are familiar with the MEF fundamentals (if not you should read this post):

[Export (typeof(MyFactory))]
[PartExportsInherited]
public abstract class MyFactory {
public abstract object Create(object bodyOfMsgBase);
public abstract bool CanHandle<T> ();
}
public class MyFactoryOfDataTable: MyFactory  {
public override object Create ( object bodyOfMsgBase ) {
return new MyGenericType<DataTable>(bodyOfMsgBase as DataTable);
}

public override bool CanHandle<T> () {
return typeof (DataTable) == typeof (T);
}
}

You can later consume the factory as demonstrate in the following code:

var container = new CompositionContainer (
new AssemblyCatalog(Assembly.GetExecutingAssembly()));

ICollection<MyFactory> aPlugIns=container.GetExportedObjects<MyFactory>();
var plugIn = (from item in aPlugIns
where item.CanHandle<string>()
select item).SingleOrDefault();
var instance = plugIn.Create (“Hellow world”);

Summary
We so that creating generics at runtime is possible but it can be costly using reflection.

You can download the code sample here.

No comments: