如何创建从封闭泛型类型派生的动态类型

时间:2011-11-08 17:03:30

标签: c# .net types reflection.emit

我正在尝试将任意数量的类型动态组合到一个继承所有这些类型的新类型。目前它应该只适用于接口。

我完全清楚存在许多陷阱和严重的性能影响,但这仅用于我的测试代码 - 更具体地说,用于为多个接口创建模拟。

所以,基本上我有一个能够创建这些类型的类(TypeBuilder - 见下面的代码)。它对“简单”类型非常有用。但我希望能够传递它封闭的泛型类型。在使用我当前的实现尝试此操作时,当我尝试创建动态类型(通过TypeLoadException)时会抛出TypeBuilder.CreateType

我是否必须告诉TypeBuilder新类型是泛型类型,尽管它只来自封闭的泛型类型?如果是,我该怎么做?

这就是我使用它的方式:

MultiTypeBuilder multiTypeBuilder = 
    new MultiTypeBuilder(Guid.NewGuid().ToString());   

multiTypeBuilder.SetBaseType(typeof(IFoo));
multiTypeBuilder.SetBaseType(typeof(IBar<IFoo>));
multiTypeBuilder.SetBaseType(typeof(IBaz));

Type multiType = multiTypeBuilder.CreateType();

这是我目前的实现(简化了一点):

private class MultiTypeBuilder
{
    private readonly TypeBuilder m_TypeBuilder;

    public MultiTypeBuilder(string name)
    {
        ModuleBuilder multiTypeModule = GetMultiTypeModule();

        TypeAttributes attributes = TypeAttributes.Interface | TypeAttributes.SpecialName | TypeAttributes.Abstract | TypeAttributes.Public;

        m_TypeBuilder = multiTypeModule.DefineType(name, attributes);
    }

    public void SetBaseType(Type baseType)
    {
        m_TypeBuilder.AddInterfaceImplementation(baseType);
    }

    public Type CreateType()
    {
        return m_TypeBuilder.CreateType();
    }

    private static ModuleBuilder GetMultiTypeModule()
    {
        AssemblyName assemblyName = new AssemblyName(c_DynamicAssemblyName);
        AssemblyBuilder assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
        return assemblyBuilder.DefineDynamicModule("MultiTypeAssembly");
    }
}

感谢您的支持!

2 个答案:

答案 0 :(得分:1)

您需要为接口定义(虚拟抽象)方法,因为您要创建抽象类,而不是接口。一些陷阱:

  1. 在枚举接口上的方法时,它不会包含来自继承接口的方法。您必须以递归方式遍历继承的接口,以及它们继承的接口等,以便找到您需要定义的所有方法。

  2. 当您遍历接口时,当两个接口从同一接口继承时,您需要处理这种情况,这样您就不会尝试两次创建该方法。

  3. 如果您有两个包含具有相同签名的方法的接口,则需要创建显式实现。这些不是抽象虚拟的(至少如果你想遵循C#约定),所以你需要发出一些IL代码来转发到其他一些虚拟抽象方法。


  4. 实际上,我刚注意到你实际上没有指定它是类型属性中的类。您需要包含TypeAttributes.Class或TypeAttributes.Interface。在后一种情况下,您不需要完成上述所有工作(如果我没记错的话,您将不需要抽象。)

答案 1 :(得分:1)

对我感到羞耻。

正如VirtualBlackFox所说,我的略微浓缩的例子有效。在我的“真实”代码中,我通过组合需要组合的类型的FullNames来创建动态类型的名称。当与泛型类型一起使用时,这显然会产生无效的类型名称(我发现例如[无效,如果您考虑它就有意义。)

如果我从生成的typename中删除任何非字母或数字字符,那么一切都像魅力一样。

感谢您的回答/评论!

相关问题