我有一个C#.Net 4.0应用程序,它使用启用了CLR的C ++ DLL来托管C ++ ActiveX控件。 DLL具有加载OCX参数的主要功能,并使用XML.Serializer实现此目的。
当所有组件都在MS Visual Studio .Net 2003和.Net 1.1中运行的C#应用程序中构建时,此堆栈工作正常。
但是,当整个模块迁移到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() 抛出异常。
请注意,'LoadNeither'上下文的位置路径包含代字号(〜)字符。 “默认”上下文具有完整路径。
ActiveX控件的互操作DLL由VS2010自动生成。
我想知道导致异常的原因。 这是路径中的不匹配吗?我不确定,但我认为DLL只加载了一次。
或者是背景中的不匹配? 如果是由于上下文不匹配,我们如何确保Interop模块的加载上下文,如C ++ ActiveX控件? 或者,我们可以指定Xml.Serializer来加载包含Default上下文中的序列化类的DLL吗?
我到处寻找,我找不到解决方案。我梳理互联网的次数越多,这对我来说就越神秘。提前谢谢。
答案 0 :(得分:1)
但我认为DLL只加载了一次
不,它装了两次。这就是问题,.NET类型的标识不仅仅是命名空间+类型名称,它还包括从中加载的程序集。它是一个DLL Hell对策,它确保您不能从具有冲突定义的不同DLL中多次加载相同的类型。
“LoadNeither”上下文是您问题的提示。你以某种方式加载这个组件。这样做的常用方法是使用Assembly.LoadFile(),这是一种非常危险的方法,只应在故意不希望类型匹配的特殊情况下使用。你应该总是使用LoadFrom(),但是如果可以的话,真的很喜欢Load()。通常可以将DLL放在正确的目录中,或者使用app.exe.config文件中的<probing>
元素。
获得版本0.0.0.0不是很健康btw,[AssemblyVersion]在.NET中是一个非常大的问题。
答案 1 :(得分:0)
这很奇怪,但是当我们使用static_cast
时没有发生异常MyClass* obj = static_cast<MyClass*>(serializer->Deserialize(reader));
虽然这个答案并没有真正解决模块被加载两次的问题,但这种解决方法可能会帮助那些人。