Tuesday, April 10, 2012

Dynamically create type and call constructor of base-class

I need to create a class dynamically. Most things work fine but i'm stuck in generating the constructor.


AssemblyBuilder _assemblyBuilder =
         AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("MyBuilder"),                                                        AssemblyBuilderAccess.Run);
 
 ModuleBuilder _moduleBuilder = _assemblyBuilder.DefineDynamicModule("MyModule");
 
 public static object GetInstance<TSource, TEventArgs>(this TSource source, string eventName)
     where TSource : class
 {
     var typeName = "MyTypeName";
     var typeBuilder = _moduleBuilder.DefineType(typeName, TypeAttributes.Class | TypeAttributes.Public);
 
     // create type like class MyClass : GenericType<MyClass, TSource, TEventArgs>
     var baseNotGenericType = typeof(GenericType<,,>);
     var baseType = baseNotGenericType.MakeGenericType(typeBuilder, typeof(TSource), typeof(TEventArgs)); 
     typeBuilder.SetParent(baseType);
 
 
     // the base class contains one constructor with string as param
     var baseCtor = baseNotGenericType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(string) }, null);
 
     var ctor = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard | CallingConventions.HasThis, new Type[0]);
     var ilGenerator = ctor.GetILGenerator();
 
     // i want to call the constructor of the baseclass with eventName as param
     ilGenerator.Emit(OpCodes.Ldarg_0); // push "this"
     ilGenerator.Emit(OpCodes.Ldstr, eventName); // push the param
     ilGenerator.Emit(OpCodes.Call, baseCtor);
     ilGenerator.Emit(OpCodes.Ret);
 
     var type = typeBuilder.CreateType();
 
     // return ...
 }
 


On call of the constructor i'm getting a BadImageFormatException. What am i doing wrong?


As requested:


The BaseClass looks something like this:


public abstract class GenericType<GT, TEventSource, TEventArgs> : BaseClass
     where GT: GenericType<GT, TEventSource, TEventArgs>, new()
     where TEventArgs : EventArgs
     where TEventSource : class
 {
     protected GenericType(string eventName)
     {
         _eventName = eventName;
     }
     // ...
 }
 


What i would like to have as a result in runtime:


public class MyType : BaseClass<MyType, ConcreteSourceType, ConcreteEventArgsType>
 {
     protected MyType() : base("SomeName")
     {
 
     }
 }
 



Answer:

I think the problem is that you're trying to call the constructor of the open generic typeGenericType<GT, TEventSource, TEventArgs>, but you need to call the constructor of the closed type BaseClass<MyType, ConcreteSourceType, ConcreteEventArgsType>. The solution to the seems simple:
var baseCtor = baseType.GetConstructor(
    BindingFlags.NonPublic | BindingFlags.Instance, null,
    new[] { typeof(string) }, null);
The problem is that this doesn't work and throws NotSupportedException. So, it seems getting the constructor of a generic type, where one of the parameters is a TypeBuilder is nut supported.
Because of that, I think what you want is not possible using Reflection.Emit, unless there is some hack to work around this.
EDIT: A-HA! I had to dive deep into Reflection.Emit in Reflector (although looking at the right place in the documentation would have worked too), but I found it: there is a special method exactly for this: the staticTypeBuilder.GetConstructor(). So this should work:
var baseNonGenericCtor = baseNotGenericType.GetConstructor(
    BindingFlags.NonPublic | BindingFlags.Instance, null,
    new[] { typeof(string) }, null);
var baseCtor = TypeBuilder.GetConstructor(baseType, baseNonGenericCtor);

No comments:

Post a Comment