转换为基类会抛出InvalidCastException

时间:2012-04-05 01:28:20

标签: c# casting xml-deserialization

我的一个程序集包含以下“提供程序”类型:

InheritanceTree

我还有一个XML文件,它使用DeviceInfoProvider基类保存提供者信息。简化版本如下所示:

<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的运行时类型是预期的派生类,但我无法将其成功转换为基类型。

我错过了什么?

2 个答案:

答案 0 :(得分:2)

您的问题可能是您正在LoadFrom上下文中的assembly.dll类型中创建实例(GenericProvider,SbRioI2CProvider)。然后,您尝试按名称转换为该程序集中的类型(DeviceInfoProvider)。这隐式使用Load上下文。来自同一程序集但在不同上下文中加载的类型被运行时视为不同类型,因此转换失败并且您将获得null。 This文章提供了对程序集绑定上下文的一些补充说明。

要使此转换成功,您需要将LoadFrom上下文中加载的Assembly放入Load上下文中。有几种方法可以做到这一点。一种方法是将程序集放入GAC。另一种方法是从应用程序库中删除assembly.dll,以便通过探测找不到它。然后使用AppDomain.AssemblyResolve事件加载通过LoadFrom获得的Assembly

答案 1 :(得分:0)

调用反射类型的构造函数不会创建它的实例。

要创建反射类型的实例,请调用Activator.CreateInstance

看起来这行应该是:

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

这会导致instance属于object类型,但现在您可以将它投射到任何您想要的位置。

请参阅:http://msdn.microsoft.com/en-us/library/wccyzw83.aspx