动态创建类型并调用基类的构造函数 [英] Dynamically create type and call constructor of base-class

查看:111
本文介绍了动态创建类型并调用基类的构造函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要动态创建一个类.大多数事情都可以正常工作,但是我被困在生成构造函数中.

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

在调用构造函数时,我遇到了BadImageFormatException.我在做什么错了?

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

根据要求:

BaseClass看起来像这样:

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

    }
}

推荐答案

我认为问题是您正在尝试调用开放通用类型GenericType<GT, TEventSource, TEventArgs>的构造函数,但是您需要调用封闭类的构造函数键入BaseClass<MyType, ConcreteSourceType, ConcreteEventArgsType>.解决方案似乎很简单:

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);

问题是这不起作用并抛出NotSupportedException.因此,似乎支持通用类型的构造函数,其中参数之一是TypeBuilder.

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.

因此,我认为使用Reflection.Emit不可能实现您想要的一切,除非有一些技巧可以解决此问题.

Because of that, I think what you want is not possible using Reflection.Emit, unless there is some hack to work around this.

编辑:A-HA!我不得不深入思考Reflection.Emit在Reflector 中(尽管在文档中查看正确的位置也是可行的) ,但我发现它:有一个特殊之处完全适合此方法的方法:静态TypeBuilder.GetConstructor() .所以这应该工作:

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);

这篇关于动态创建类型并调用基类的构造函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆