13

クラスを動的に作成する必要があります。ほとんどのものは正常に動作しますが、コンストラクターの生成に行き詰まっています。

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

    }
}
4

2 に答える 2

12

問題は、オープンジェネリック型のコンストラクターを呼び出そうとしていることだと思いますがGenericType<GT, TEventSource, TEventArgs>、クローズド型のコンストラクターを呼び出す必要がありますBaseClass<MyType, ConcreteSourceType, ConcreteEventArgsType>。の解決策は簡単に思えます:

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

問題は、これが機能せず、をスローすることNotSupportedExceptionです。したがって、パラメーターの1つTypeBuilderがナットでサポートされているジェネリック型のコンストラクターを取得しているようです。

そのため、これを回避するためのハックがない限り、Reflection.Emitを使用して必要なことを行うことはできないと思います。

編集: 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);
于 2012-04-10T15:19:22.777 に答える
5

これを行う最も簡単な方法は、抽象クラスと派生クラスを単純なアセンブリにコンパイルし、アドインとして利用可能な「Reflection.Emit」言語を使用して Reflector で開くことです。

http://reflectoraddins.codeplex.com/

リフレクター: Reflection.Emit 言語

はい、それはそれが聞こえるほどクールです:)

于 2012-04-10T15:27:36.143 に答える