2012-04-10 1 views
10

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

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

    } 
} 
+0

Посмотрите здесь http://stackoverflow.com/questions/893423/how-do-create-a-dynamic-class-in-c-sharp-4 –

+0

Не очень полезно или я что-то пропустил? Я хочу наследовать от базового класса и называть его базовым конструктором, у которого есть аргумент. – SACO

+0

Пробуйте также эту ссылку http://blogs.msdn.com/b/cburrows/archive/2009/04/22/dynamic-base-classes-in-c-4.aspx –

ответ

10

Я думаю, что проблема в том, что вы пытаетесь вызвать конструктор открытого типа типа 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 (хотя бы посмотрел и на правильное место в документации, сработало бы тоже), но я нашел: для этого есть специальный метод: the static TypeBuilder.GetConstructor(). Так что это должно работать:

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

Так что я с нетерпением жду взлома :) – SACO

+0

Собственно, это возможно и это совсем не хак, см. править. – svick

+0

Кстати, такие вопросы, которые заставляют меня узнать что-то новое, являются лучшими. – svick

3

Самый простой способ сделать это было бы составить свои абстрактные и производные классы в простую сборку, а затем открыть их в рефлектор с помощью «Reflection.Emit» доступный язык как надстройка от:

http://reflectoraddins.codeplex.com/

Reflector: Reflection.Emit language

Да, это так круто, как это звучит :)

+0

Вы уверены, что это сработает в этом конкретном случае? – svick

+0

Если ваше искомое определение класса допустимо C# и будет компилироваться, тогда да. – x0n

+0

Ну, код, который он генерирует в этом случае, не имеет большого смысла и не поможет OP. Это потому, что он использует 'typeof (MyType)', что не имеет смысла, когда вы создаете этот тип. И использование 'typeBuilder' вместо этого приведет к' NotSupportedException'. – svick

 Смежные вопросы

  • Нет связанных вопросов^_^