У меня есть приложение C # .Net 4.0, в котором размещается элемент управления C ++ ActiveX, использующий C ++ DLL с включенным CLR. 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 ()
Исключение было брошено.
Обратите внимание, что контекст «LoadNeither» имеет путь к тильда (~) персонаж. Контекст по умолчанию имеет полный путь.
DLL взаимодействия для элемента управления ActiveX автоматически генерируется VS2010.
Интересно, что вызывает исключение.
Это несоответствие в пути? Я не уверен, но я думаю, что DLL была загружена только один раз.
Или это несоответствие по контексту?
Если это происходит из-за несоответствия контекста, как мы можем убедиться, что контекст загрузки для модулей Interop, таких как элементы управления C ++ ActiveX?
Или мы можем указать Xml.Serializer для загрузки DLL, содержащей классы сериализации в контексте по умолчанию?
Я искал везде, и я не мог найти решение. Чем больше я прочесываю интернет, тем больше это становится для меня загадкой. Заранее спасибо.
но я думаю, что DLL была загружена только один раз
Нет, он загрузился дважды. И это проблема, идентичность типа .NET — это не просто пространство имен + имя типа, оно также включает сборку, из которой он был загружен. Это контрмера DLL Ад, она гарантирует, что вы не можете иметь один и тот же тип, загруженный более одного раза из разных DLL с конфликтующим определением.
Контекст «LoadNeither» является подсказкой к вашей проблеме. Вы каким-то образом загружаете эту сборку необычным способом. Обычный способ сделать это — использовать Assembly.LoadFile (), очень опасный метод, который следует использовать только в очень особых случаях, когда вы намеренно не хочу, чтобы типы соответствовали Вы должны всегда использовать LoadFrom (), но по-настоящему отдавать предпочтение Load (), когда можете. И вы обычно можете, поместив DLL в нужную директорию или используя <probing>
элемент в файле app.exe.config.
Получение версии 0.0.0.0 также не очень полезно, кстати, [AssemblyVersion] очень важна для .NET.
Это странно, но исключение не произошло, когда мы использовали static_cast
MyClass* obj = static_cast<MyClass*>(serializer->Deserialize(reader));
Хотя этот ответ не решает проблему загрузки модуля дважды, этот обходной путь может помочь кому-то там.