13

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")
    {

    }
}
Daniel Bişar
  • 2,663
  • 7
  • 32
  • 54
  • Have a look here http://stackoverflow.com/questions/893423/how-do-create-a-dynamic-class-in-c-sharp-4 – NoWar Apr 10 '12 at 14:10
  • Not really helpful or did i miss something? I want to inherit from a baseclass and call it's base constructor which have an argument. – Daniel Bişar Apr 10 '12 at 14:13
  • Try this link as well http://blogs.msdn.com/b/cburrows/archive/2009/04/22/dynamic-base-classes-in-c-4.aspx – NoWar Apr 10 '12 at 14:14
  • This link is about a dynamic as baseclass. I need a dynamically generated subclass from a predefines generic baseclass. – Daniel Bişar Apr 10 '12 at 14:36
  • How do the generic parameters work here? Is this code in a class (or method) that has generic parameters `TSource` and `TSource`? – svick Apr 10 '12 at 14:51
  • I edit the question to answer your question. I let out the return statement because i am accessing some static property and so on; just to keep it simple. – Daniel Bişar Apr 10 '12 at 15:01
  • please paste the desired class definition also in regular C# to make the question clearer (i.e. what the class would look like if you defined it declaratively.) – x0n Apr 10 '12 at 15:02

2 Answers2

12

I think the problem is that you're trying to call the constructor of the open generic type GenericType<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 static TypeBuilder.GetConstructor(). So this should work:

var baseNonGenericCtor = baseNotGenericType.GetConstructor(
    BindingFlags.NonPublic | BindingFlags.Instance, null,
    new[] { typeof(string) }, null);
var baseCtor = TypeBuilder.GetConstructor(baseType, baseNonGenericCtor);
svick
  • 236,525
  • 50
  • 385
  • 514
5

The easiest way to do this would be to compile up your abstract and derived classes into a simple assembly, then open them in Reflector using the "Reflection.Emit" language available as a addin from:

http://reflectoraddins.codeplex.com/

Reflector: Reflection.Emit language

Yes, that's as cool as it sounds :)

x0n
  • 51,312
  • 7
  • 89
  • 111
  • If your desired class definition is valid c# and will compile, then yes. – x0n Apr 10 '12 at 15:44
  • Well, the code it generates in this case doesn't make much sense and wouldn't help the OP. That's because it uses `typeof(MyType)`, which doesn't make sense when you're building that type. And using `typeBuilder` instead would lead to a `NotSupportedException`. – svick Apr 10 '12 at 15:58
  • Good point... I see that now. I guess recursive parametric types are going to be tough. :) – x0n Apr 10 '12 at 22:54
  • Sorry for late "credit" :) I'm still trying if it really works. But thanks for the idea! – Daniel Bişar Apr 11 '12 at 07:35