.NET 4.0迁移后引用.NET 1.0程序集时出现System.TypeLoadException异常

3
有一个项目从.NET 3.5迁移到了.NET 4.0。该项目引用了.NET 1.0程序集,这些程序集是COM对象的包装器。这些.NET 1.0程序集和COM对象是外部公司的产品。该项目可以编译,但在运行时,软件在第一个引用那些1.0程序集中定义的对象的时候会抛出异常: System.TypeLoadException:无法从程序集“ESRI.MapObjects2.Core,Version = 2.4.1.0,Culture = neutral,PublicKeyToken = 8fc3cc631e44ad86”中加载结构“ESRI.MapObjects2.Core.ShapeTypeConstants”。 该结构被标记为符合类型等价性,但它具有静态或非公共字段。实际的“结构”是一个枚举,在反射器中它看起来像这样: [Guid("B027CAB1-6908-11D2-AF98-006097DA3688")] public enum ShapeTypeConstants { moShapeTypeEllipse = 0x1a, moShapeTypeLine = 0x16, moShapeTypeMultipoint = 0x18, moShapeTypePoint = 0x15, moShapeTypePolygon = 0x17, moShapeTypeRectangle = 0x19 } 内部异常为null。我可以看到HRESULT为0x80131522(-2146233054),这意味着COR_E_TYPELOAD。我认为我没有缺少本机dll或程序集,因为我们的.NET工作正常(它使用相同的代码,相同的引用)。 如何修复此异常?是否有像在dll的配置文件中指定requiredRuntime或在csproj的Reference部分中指定requiredTargetFramework这样简单的方法?

给定的 TypeLoadExceptionInnerException 是什么? - Shani Elharrar
请使用供应商支持论坛 - Hans Passant
汉斯:我已经做了。MapObjects2是一个已停用的产品。我期望被引导到一个新的ArcGIS API,但我正在寻找一个更简单的解决方案。http://forums.arcgis.com/threads/81091-Game-over-The-structure-is-marked-as-eligible-for-type-equivalence-but-it-has-... - Csaba Toth
Shani:我已经在我的原始帖子中添加了答案。没有InnerExcpetion,但我看到了一个HResult。 - Csaba Toth
汉斯:这是一个供应商线程,有类似的问题,但那个家伙没有评论他如何解决问题。我正在撞墙:http://forums.arcgis.com/threads/43094-Could-not-load-the-structure-ESRI.MapObjects2.Core.CancelActionConstants - Csaba Toth
2个回答

0

如果情况艰难,那我也可以强硬起来。

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

那么为什么我们不直接将它们设为公共:

  1. 使用ildasm反汇编源代码。
  2. 用public替换private作用域限定符(如果我记得正确的话:替换了49个位置)。
  3. 最后,使用修改后的IL从ilasm编译dll。

大功告成!生成的dll(ESRI.MapObjects2.Core.dll)大小为311.296字节,而原始文件长达323.584字节,这让我仍然有点怀疑。但是如果我用修改后的dll覆盖GAC中的原始dll,一切都能正常工作,我们的软件不再崩溃。我无法确认所有功能是否100%正常,因为我不太了解我们软件的GIS部分。但是到目前为止,我所做的还可以。 可能会让人担心的是:如果公共变量的存在会改变任何结构布局,它可能会导致枚举值的移位或其他混乱。但希望它不会搞乱任何东西。这只是一个快速的hack,在生产环境中需要在MapObjects42安装后覆盖GAC中的ESRI.MapObjects2.Core.dll。唉。 所以我不一定建议任何人这样做,但它似乎有效,并给了我一些满足感,一种复仇的感觉。黑客行为让我在一天结束时感到一点幸福。


如何编辑Interop程序集,简单易懂:http://msdn.microsoft.com/zh-cn/library/8zbc969t.aspx - Csaba Toth

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”的引用。这将使用.NET代码包装COM组件,实际上可以在VS 2010中运行。
然后对于视觉组件,请在工具箱中右键单击并选择“选项卡”,选择“COM 组件”选项卡中的“MapObjects 2.3 Map Control”,然后您将能够将该控件添加到表单中。在我的情况下,我不得不将其添加到表单中,然后将其删除,以便 Visual Studio 自动将对“AxMapObjects2”的引用添加到项目中。此引用包含了可视化控件及其某些支持类型。然后,我只需用 AxMapObjects2.AxMap 替换我们旧的 AxMap 引用,用 MapObjects2.Typename 替换其他类型,一切就可以正常工作了(至少到目前为止)。

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


长期的解决方案可以是在我的特定情况下过渡到更新的API(ArcGIS)。但这需要比dll hack更多的工作。 - Csaba Toth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接