2012-04-05 42 views
3

我的一個組件包含以下「供應商」類型:鑄造基類引發InvalidCastException

InheritanceTree

我也有持有使用DeviceInfoProvider基類供應商信息的XML文件。一個簡化的版本是這樣的:

<DeviceInfoProvider Type="SbRioI2CProvider" Assembly="assembly.dll" > 
</DeviceInfoProvider> 
<DeviceInfoProvider Type="GenericProvider" Assembly="assembly.dll" > 
</DeviceInfoProvider> 

在運行時,我XML字段映射到我的變量:

assembly.dll ⇒ assemblyPath 
Type   ⇒ typeName 

和讀取XML後,使用下面的代碼來實例化我的類型:

var assembly = Assembly.LoadFrom(assemblyPath); 

var type = (from t in assembly.GetTypes() 
      where t.IsPublic && t.Name == typeName 
      select t).FirstOrDefault(); 

if (type != null) 
{ 
    instance = type.GetConstructor(Type.EmptyTypes).Invoke(null); 
} 

正如所料,這會適當地生成我的對象。

問題是當我嘗試投實例作爲一個基類對象:

using (var provider = instance as DeviceInfoProvider) 
{ 
    // provider is null! 
} 

instance運行時類型是預期的派生類,但我不能成功地將它轉換爲它的基本類型。

我錯過了什麼?

+0

變量'typeName'的值是什麼?從XML讀取一個常量字符串值「DeviceInfoProvider」? – llj098 2012-04-05 02:36:43

+0

都是在同一個組件中的這些類型? – 2012-04-05 03:10:45

+0

@mikez:從XML加載的類型不需要全部在同一個程序集中 – 2012-04-05 19:12:47

回答

2

你的問題可能是您從類型assembly.dll在LoadFrom上下文創建實例(GenericProvider,SbRioI2CProvider)。然後,您正嘗試按名稱將其轉換爲該程序集中的類型(DeviceInfoProvider)。這隱含地使用Load上下文。運行時將相同程序集中的但加載到不同上下文中的類型視爲不同類型,因此轉換失敗並且您將獲得空值。 This文章提供了一些關於程序集綁定上下文的額外解釋。

爲了使這個轉換成功,您需要將在LoadFrom上下文中加載的Assembly置於Load上下文中。有幾種方法可以做到這一點。一種方法是將程序集放入GAC。另一種方法是從應用程序庫中刪除assembly.dll,以便通過探查找不到它。然後使用AppDomain.AssemblyResolve事件加載您通過LoadFrom獲得的Assembly

+0

感謝您的解釋和鏈接。給這個集會一個強有力的名字做了訣竅! – 2012-04-05 20:44:39

0

調用反射類型的構造函數不會創建它的一個實例。

要創建反射類型的實例,請致電Activator.CreateInstance

它看起來像這條線應該是:

if (type != null) { 
    instance = Activator.CreateInstance(type) 
} 

這將導致instanceobject型的,但現在你可以將它轉換爲任何你想要的。

請參見:http://msdn.microsoft.com/en-us/library/wccyzw83.aspx

+0

那麼,Invoke方法的返回值是什麼? – llj098 2012-04-05 02:32:50

+0

你讓我了。 http://msdn.microsoft。com/en-us/library/6ycw1y17.aspx'與構造函數關聯的類的一個實例。我從來沒有見過以前創建過的反射類型的實例。 – 2012-04-05 02:35:12

+0

如果你進一步過濾你的Linq表達式來排除那些不是從'DeviceInfoProvider'派生的類型,你仍然會得到你想要的類型嗎? – 2012-04-05 02:40:29