2011-11-08 68 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

是的,我已經添加了屬性。而且在使用公共接口時也會發生...... –