Monday, March 09, 2009

Dynamic Interface Addition to existing Class using Reflection

I recently went through an article by Eric McMullen. The power of reflection and dynamic code was so well depicted in the article.

We know how to create a dynamic code using reflection. But what i liked about this bit of article from Eric was how an already existing type was wrapped by a Interface dynamically at the runtime. Now, isn't that a useful feature to have ??

Not sure ?? Think in this manner. You have an interface with a method "Name". You also have a class "MyName" which DOES NOT implement the interface but has a virtual method "Name". It is obvious that you cannt create a referance of the interface for the class. But the point , is with Dynamic extension, we could just well do it.

How do we do it ? lets have a look at the code.

First and foremost thing you would want is have an assembly, in this case a dynamic one. So let us go ahead and degfine it first.

I have create a function which would take the target type and interface that needs to be implement as parameters.

public object GetNewImplementation(System.Type TargetType,System.Type InterfaceToImplement)
{
AssemblyName an = new AssemblyName();
an.Name = "ExtendedTypes";
assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.RunAndSave);
moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler ( CurrentDomain_AssemblyResolve);
Type t = Subclass (moduleBuilder, TargetType, InterfaceToImplement, "ClassTest1");
return (Activator.CreateInstance(t,true)) as object;
};



As you can see i am calling a SubClass method in later part of the method. This is the magic method which does the trick for us.

public Type Subclass(ModuleBuilder builder, Type target, Type interfaceToImplement, string newTypeName)
{
TypeAttributes attributes = TypeAttributes.Public;

TypeBuilder tb =builder.DefineType("ConsoleApplication1.DynamicClassTest1", attributes,target);
tb.AddInterfaceImplementation(interfaceToImplement);

Type subClass = tb.CreateType();
return subClass;
}

private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
Assembly returnVal = null;
if(args.Name == this.assemblyBuilder.FullName)
{
returnVal = assemblyBuilder;
}
return returnVal;
}



Now is that cool ?