2011-11-08 35 views
1

我想动态地将任意数量的类型组合到一个继承所有这些类型的新类型中。目前它只能用于接口。如何创建从一个封闭的泛型派生的动态类型

我绝对知道有很多陷阱和沉重的性能影响,但这仅用于我的测试代码 - 更具体,用于创建多个接口嘲笑。

所以,基本上我有一个类(TypeBuilder - 见下面的代码),它能够创建这些类型。它适用于“简单”类型。但我希望能够通过它关闭泛型类型。当试图用我目前的实现时,当我尝试创建动态类型(通过TypeBuilder.CreateType)时抛出TypeLoadException

我必须告诉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"); 
    } 
} 

感谢您的支持!

+0

在你的例子中,定义了IBar 这样T可能只是一个接口?如果没有,你可以试试。 – Fantius

+0

不,它不是,它不是,因为我不知道编译时的类型。 –

+1

用空IBar,IBaz和IFoo接口在LINQPad中编译你的代码可以正常工作,你可以发布一些失败的代码吗?查看http://ideone.com/is5gU的输出 –

回答

1

耻辱。

由于VirtualBlackFox声明我稍微压缩的示例工程。在我的“真实”代码中,我通过结合需要组合的类型的FullNames来创建动态类型的名称。与泛型类型一起使用时,显然会产生一个无效的类型名称(我发现例如[是无效的,如果您考虑它,这是有意义的)。

如果我从生成的类型名称中删除任何非字母或数字字符,则一切就像魅力一样。

感谢您的回答/评论!

1

您需要定义的接口(虚拟抽象)方法,如你创建一个抽象类,而不是一个接口。几个小问题:

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

  2. 当你走的接口,你需要处理的情况下,当两种接口相同的接口继承,所以你不尝试两次创建方法。

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


其实,我只注意到你实际上并没有指明它是在类型属性的类。您需要包含TypeAttributes.Class或TypeAttributes.Interface。在后一种情况下,你不需要做所有上述工作的(你将不再需要抽象的,如果我没有记错。)在我

+0

感谢Dan的回答,但为了简单起见,所有类型以及返回的动态类型都是接口。我相应地更新了我的问题中的TypeAttributes。但问题仍然是一样的。 –

+0

@弗洛里安,做任何接口都有内部可视性?如果是这样,您需要将'[assembly:InternalsVisibleTo(/ * c_DynamicAssemblyName * /)]'添加到包含内部接口的程序集的PropertyInfo.cs中。 –

+0

是的,我已经添加了属性。而且在使用公共接口时也会发生...... –