2012-04-05 65 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