Подтвердить что ты не робот

Динамически создавать конструктор типов и вызовов базового класса

Мне нужно создать класс динамически. Большинство вещей работают нормально, но я застрял в создании конструктора.

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 ...
}

При вызове конструктора я получаю исключение BadImageFormatException. Что я делаю неправильно?

В соответствии с запросом:

BaseClass выглядит примерно так:

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;
    }
    // ...
}

Что я хотел бы иметь в результате во время выполнения:

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

    }
}
4b9b3361

Ответ 1

Я думаю, проблема в том, что вы пытаетесь вызвать конструктор открытого типа типа GenericType<GT, TEventSource, TEventArgs>, но вам нужно вызвать конструктор закрытого типа BaseClass<MyType, ConcreteSourceType, ConcreteEventArgsType>. Решение кажется простым:

var baseCtor = baseType.GetConstructor(
    BindingFlags.NonPublic | BindingFlags.Instance, null,
    new[] { typeof(string) }, null);

Проблема в том, что это не работает и бросает NotSupportedException. Таким образом, кажется, что создается конструктор родового типа, где один из параметров - TypeBuilder поддерживается гайкой.

Из-за этого я думаю, что то, что вы хотите, невозможно с помощью Reflection.Emit, если только не будет хакера, чтобы обойти это.

EDIT: A-HA! Мне пришлось глубоко погрузиться в Reflection.Emit in Reflector (хотя поиск правильного места в документации тоже сработал бы), но я нашел: есть специальный метод для этого: статический TypeBuilder.GetConstructor(). Поэтому это должно работать:

var baseNonGenericCtor = baseNotGenericType.GetConstructor(
    BindingFlags.NonPublic | BindingFlags.Instance, null,
    new[] { typeof(string) }, null);
var baseCtor = TypeBuilder.GetConstructor(baseType, baseNonGenericCtor);

Ответ 2

Самый простой способ сделать это - скомпилировать ваши абстрактные и производные классы в простую сборку, а затем открыть их в Reflector, используя язык "Reflection.Emit", доступный как addin из:

http://reflectoraddins.codeplex.com/

Reflector: Reflection.Emit language

Да, это так круто, как кажется:)