.NET 4.0迁移后引用.NET 1.0程序集的System.TypeLoadException

时间:2013-04-01 17:43:17

标签: .net com migration arcgis

有一个项目从.NET 3.5迁移到.NET 4.0。该项目有一些.NET 1.0程序集的引用,它们是COM对象的包装器。这些.NET 1.0程序集和COM对象是外部公司的产品。项目编译,但在运行时,软件引用这些1.0程序集中定义的对象的第一点引发异常:

System.TypeLoadException: Could not load the structure 'ESRI.MapObjects2.Core.ShapeTypeConstants' from assembly 'ESRI.MapObjects2.Core, Version=2.4.1.0, Culture=neutral, PublicKeyToken=8fc3cc631e44ad86'.

该结构被标记为有资格进行类型等效,但它具有静态或非公共字段。实际的“结构”是一个枚举,在Reflector中看起来像这样:

[Guid("B027CAB1-6908-11D2-AF98-006097DA3688")] public enum ShapeTypeConstants { moShapeTypeEllipse = 0x1a, moShapeTypeLine = 0x16, moShapeTypeMultipoint = 0x18, moShapeTypePoint = 0x15, moShapeTypePolygon = 0x17, moShapeTypeRectangle = 0x19 }

内部异常为空。我可以看到HRESULT为0x80131522(-2146233054),它表示COR_E_TYPELOAD。我不认为我有任何遗漏的本机dll或程序集,因为我们的.NET工作正常(它使用相同的代码,相同的引用)。

如何修复此异常?是否有一种简单的方法,比如在csproj的参考部分中在dll的配置文件或requiredTargetFramework中指定requiredRuntime?

2 个答案:

答案 0 :(得分:0)

如果情况很糟糕,那我也可以玩粗糙。

如果我们查看实际的错误消息,它会抱怨“结构”中的“静态或非公共”字段。所谓的结构实际上是一个枚举。看似COM层上的包装枚举。有许多不同的包装器枚举,每个值都是明确指定的。每个枚举还包含一个名为“value__”的私有int变量。更具体地说,它看起来像这样: .field private specialname rtspecialname int32 value__

那么我们为什么不把它们公之于众呢?

  1. 使用ildasm反汇编源。
  2. 将私有范围限定符替换为public(如果我没记错的话:更换了49个位置)。
  3. 最后,我使用修改后的IL中的ilasm编译了一个dll。
  4. 瞧!生成的dll(ESRI.MapObjects2.Core.dll)是311.296字节,而原始的长度是323.584字节,这让我有点怀疑。但是如果我用我修改过的那个覆盖GAC中的原始dll,那么事情就会起作用,我们的软件就不会再爆炸了。我无法确认100%的所有内容都能正常运行,因为我真的不知道我们软件的GIS部分。但到目前为止我设法得到的是好的。 什么可以让人担心:如果公共变量的存在会改变任何结构布局,它可能会导致枚举值或其他混合的转移。但希望它不会混淆任何东西。这是一个快速入侵,在生产中它需要在MapObjects42安装后覆盖GAC中的ESRI.MapObjects2.Core.dll。叹。 所以我不一定向任何人提出建议,但它似乎有效,它给了我一些满足感,某种复仇感。黑客在一天结束时给了我一点快乐。

答案 1 :(得分:0)

也许是其他人的可能解决方案:省略供应商提供的.NET包装器dll,并直接从我们的项目引用底层COM组件。 Joe Parker在此主题中描述了这一点:http://social.msdn.microsoft.com/Forums/zh-CN/vblanguage/thread/81c44b22-7bdc-4379-b0f6-953e1f96adfe。 “通过将控件作为COM组件引用而不是使用MapObjects附带的.NET dll,我们能够使用MapObjects 2.3解决这个问题。从项目中删除ESRI。???引用,然后添加对COM组件的引用” ESRI MapObjects 2.3“。这将使用实际在VS 2010中运行的.NET代码包装COM组件。

然后,对于可视组件,右键单击工具箱中的“选择项目”。从“COM组件”选项卡中选择“MapObjects 2.3 Map Control”,然后您就可以将控件添加到表单中。在我的情况下,我不得不将其添加到表单然后删除它只是因此Visual Studio将自动添加对“AxMapObjects2”的引用到项目。该引用具有可视控件和一些支持类型。然后我用AxMapObjects2.AxMap和其他类型的MapObjects2.Typename替换了我们的旧AxMap引用,并且一切正常(至少到目前为止)。“

他的方法也可以推广到其他类似的情况:“app< - > vendor .NET wrapper< - > vendor COM objects”。不幸的是,这种方法在我们的案例中可能并不那么容易,因为我们不仅在应用程序中托管了COM控件,而且在我们软件的其他模块中,我们还具有导出和导入功能以及其他分散的东西。所以我不能只在那里引用GUI COM组件,我只需要在其他地方使用一些核心功能。但我想我会分享这个发现,它可能对其他人有所帮助。我100%确定不是MapObjects2和我们的应用程序将是唯一的受害者。随着越来越多的项目将迁移到.NET 4.0,仍然有一些旧的遗留负担可能会面临这种情况。