C#.Net 4.0应用程序中托管的C++ActiveX控件中出现Xml.Serializer非法强制转换异常

本文关键字:非法 Serializer Xml 异常 转换 C++ActiveX Net 应用程序 控件 | 更新日期: 2023-09-27 18:27:24

我有一个C#.Net 4.0应用程序,该应用程序使用启用CLR的C++DLL托管C++ActiveX控件。DLL的主要功能是加载OCX的参数,并为此使用XML.Serializer。

当所有组件都在MS Visual Studio.Net 2003中构建并且C#应用程序在.Net 1.1中运行时,此堆栈运行良好。

然而,当整个模块迁移到VS2010并将应用程序迁移到.Net 4.0时,由于上下文不匹配,我得到了可怕的Xml.Serializer非法强制转换异常。

异常发生在第4行:

FileStream* fs = __gcnew FileStream( filename, FileMode::Open );
XmlReader* reader = __gcnew XmlTextReader( fs );
XmlSerializer* serializer = __gcnew XmlSerializer( __typeof(MyClass) );
MyClass* obj = __try_cast<MyClass*>(serializer->Deserialize(reader)); 

以下是例外声明:

[A]MyClass cannot be cast to [B]MyClass.
Type A originates from 'ParameterModule, Version=0.0.0.0, Culture=neutral,      PublicKeyToken=null' in the context 'Default'
at location 'C:'path'to'module'ParameterModule.dll'.
Type B originates from 'ParameterModule, Version=0.0.0.0, Culture=neutral,  PublicKeyToken=null' in the context 'LoadNeither'
at location 'C:'path'to'modu~'ParameterModule.dll'. 

位于ParameterModule.ParaClass.execute_DeSerialize()引发了异常。

请注意,"LoadNever"上下文的位置路径带有波浪号(~)字符。"Default"上下文具有完整路径。

ActiveX控件的互操作DLL由VS2010自动生成。

我想知道是什么导致了这个异常。是路径不匹配吗?我不确定,但我认为DLL只加载过一次。

还是上下文不匹配?如果是因为上下文不匹配,我们如何确保像C++ActiveX控件这样的Interop模块的加载上下文?或者,我们可以指定Xml.Serializer来加载默认上下文中包含序列化类的DLL吗?

我到处找都找不到解决办法。我越是在网上搜索,这对我来说就越是一个谜。提前谢谢。

C#.Net 4.0应用程序中托管的C++ActiveX控件中出现Xml.Serializer非法强制转换异常

但我认为DLL只加载了一次

不,它装了两次。这就是问题所在,.NET类型的标识不仅仅是名称空间+类型名,它还包括从中加载的程序集。这是一个DLL地狱对策,它确保您不能从定义冲突的不同DLL中多次加载同一类型。

"LoadNever"上下文是解决问题的线索。不知怎的,你以一种不同寻常的方式加载了这个程序集。常见的方法是使用Assembly.LoadFile(),这是一种非常危险的方法,只有在您有意不希望类型匹配的非常特殊的情况下才应该使用。您应该始终使用LoadFrom(),但在可能的情况下确实喜欢Load()。通常可以将DLL放在正确的目录中,或者使用app.exe.config文件中的<probing>元素。

获得0.0.0.0版本也不是很健康,顺便说一句,[AssemblyVersion]在.NET中是一件大事。

这很奇怪,但当我们使用static_cast 时没有发生异常

MyClass* obj = static_cast<MyClass*>(serializer->Deserialize(reader)); 

虽然这个答案并不能真正解决模块被加载两次的问题,但这个解决方法可能会对某些人有所帮助。