草庐IT

c# - 最小起订量和互操作类型 : works in VS2012, 在 VS2010 中失败?

coder 2024-05-30 原文

我有一个包含大约 500 个单元测试的 .NET 库项目。所有这些测试在 Visual Studio 2012 中运行良好。但是,我的一些测试在 Visual Studio 2010 中失败。在这些失败的测试中,我使用 起订量 模拟来自 Microsoft.Office.Interop.Excel 的几种互操作类型.尝试访问这些模拟互操作类型时,测试立即失败:

Error: Missing method 'instance class Microsoft.Office.Interop.Excel.Range [ExcelAddIn.Core] Microsoft.Office.Interop.Excel.ListRow::get_Range()' from class 'Castle.Proxies.ListRowProxy'.

这个异常意味着我忘记在我的模拟上设置适当的属性 getter。情况并非如此:
_listRowMock.Setup(m => m.Range).Returns(_rangeMock.Object);

现在我可以想象 Moq 可能不会与互操作类型一起很好地工作。但我觉得最令人费解的是,这些测试在 Visual Studio 2012 中运行良好,但在 Visual Studio 2010 中却失败了。

为什么我的 Visual Studio 会影响我的代码的行为?

更新:3-11-2012

好的,所以我把它归结为:
  • 我有两个项目; Core 和 Core.UnitTest。 Core 是实际的库,而 Core.UnitTest 是 Core 库的单元测试项目。
  • 这两个项目都引用了 Microsoft.Office.Interop.Excel 并启用了嵌入互操作类型。
  • 由于启用了 EIT,两个项目都包含自己的 Microsoft.Office.Interop.Excel 库“ View ”。该 View 包括在各自项目中使用的所有类、方法和属性。
  • 由于两个项目使用 Microsoft.Office.Interop.Excel 的不同类、方法和属性,因此两个库的嵌入类型不同。例如。 Core 中的 ListRow 具有 Index 和 Range 属性,而 Core.UnitTest 中的 ListRow 仅具有 Range 属性。
  • 尽管这两种类型不同且不共享公共(public)接口(interface)或父类(super class),但它们是 equivalent .这意味着 CLR 会将它们视为相同,并允许您跨程序集边界使用这些类型。例如。当传递给 Core 库中的方法时,来自 Core.UnitTest 的 ListRow 实例将正常工作。共享的 Range 属性将起作用,而缺少的 Index 属性将在访问时抛出 MissingMethodException。
  • 上述行为甚至适用于模拟类型。 Mock[Excel.ListRow] 的模拟对象在跨越程序集边界时可以正常工作。
  • 不幸的是,上一点中描述的行为仅在我在 Visual Studio 中构建程序集时才有效 2012 .当我在 Visual Studio 中构建我的程序集时 2010 并调试我的代码,我可以看到模拟的 ListRow 实例被传递到我的 Core 项目的方法中。在实例跨越程序集边界的那一刻,ListRow 的所有方法和属性都将失去它们的实现并抛出 MissingMethodExceptions。
  • 现在说到有趣的部分,我实际上设法通过确保 ListRow 的两种嵌入类型对齐来缓解这个问题。例如。为了让编译器在两个项目中创建相同的 ListRow View ,我确保在我的 UnitTest 项目中使用了完全相同的方法和属性。这意味着添加虚拟行,如:var dummy = listRow.Index。一旦我让编译器创建了与我嵌入的 ListRow 类型相同的 View ,该实例就可以跨越程序集边界而不会丢失其实现。

  • 问题仍然存在:是什么导致了 Visual Studio 2010 和 Visual Studio 2012 之间的这种行为差异?

    更新:2012 年 9 月 11 日

    演示解决方案 :http://temp-share.com/show/KdPf6066h

    我创建了一个小解决方案来演示效果。该解决方案由一个库和一个 UnitTest 项目组成。两者都引用启用了 EIT 的 Microsoft.Office.Interop.Excel.Range。该测试在 VS2012 中运行良好,但在 VS2010 中抛出 MissingMethodException。在测试中取消注释虚拟行将使其在 VS2010 中工作。

    最终更新:29-12-2012

    我很抱歉更新晚了。我的一个同事找到了一个解决方案,但是我无法在我的机器上重现它。与此同时,我们公司已经切换到 TFS2012,所以这对我来说不再是一个阻塞问题。我的同事得出的两个最重要的结论是:
  • “Any CPU”平台的语义已从 Visual
    Studio 2010 到 Visual Studio 2012。这将导致不同的
    .DLL 的生成取决于您使用的是 VS2010 还是
    VS2012。
  • 这两个项目都引用了不同版本的 Microsoft.Office.Interop.Excel。

  • 我检查了我的项目并整理了引用资料,但没有任何区别。之后,我在 VS2010 和 VS2012 中尝试了不同的平台变体,但无法产生令人满意的结果。我会接受 Jeremy 的回答,因为它是最有帮助的。谢谢大家的帮助。

    最佳答案

    编辑:当我在 Visual Studio 2012 中尝试它并以 .Net 4.0 为目标时,它对我有用,只使用 .Net PIA 而不是 COM ref。同样的解决方案在 VS2010 中不起作用。

    VS2010 加载版本的 Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll's 的 10.0.30319.1和 VS2012 加载版本的 11.0.50727.1。您可以在“模块”窗口中看到不同的版本。

    我设法让它在 VS2010 中工作:



    这是我的解决方案 http://temp-share.com/show/Pf3Ypip62为了大家的方便。它包含所有起订量引用。我有 Excel 2007(即 v12) - 所以请调整对 Office 14 的引用。

    带有待测试方法的项目必须使用 PIA Microsoft.Office.Interop.Excel通过 .Net 引用选项卡。

    在单元测试项目中,您必须使用 Microsoft Excel 1X.0 Object Library通过 COM 引用选项卡 - 它是一个 ActiveX。

    The confusing thing is in Solution Explorer they are both called: Microsoft.Office.Interop.Excel



    还有一个警告,我不知道如何解决 - 您必须使用 .Net 3.5 框架 我实际上希望微软在 2012 年修复它,因为你发现了 因为我无法处理 .Net 4.0 中的所有项目。一些针对 .Net 3.5 和 4.0 的混合项目解决方案是可以的。

    我在这方面遇到了很多麻烦,请参阅此处 How do I avoid using dynamic when mocking an Excel.worksheet?还看到我问的这个问题:Mocked object doesn't have all properties shown in Intellisense - in one project but has them in the other .

    无论如何,这是让它在 VS 2010 中工作的方法。我很高兴它在 2012 年得到解决!

    关于c# - 最小起订量和互操作类型 : works in VS2012, 在 VS2010 中失败?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13202120/

    有关c# - 最小起订量和互操作类型 : works in VS2012, 在 VS2010 中失败?的更多相关文章

    1. ruby-on-rails - Railstutorial : db:populate vs. 工厂女孩 - 2

      在railstutorial中,作者为什么选择使用这个(代码list10.25):http://ruby.railstutorial.org/chapters/updating-showing-and-deleting-usersnamespace:dbdodesc"Filldatabasewithsampledata"task:populate=>:environmentdoRake::Task['db:reset'].invokeUser.create!(:name=>"ExampleUser",:email=>"example@railstutorial.org",:passwo

    2. c# - 如何在 ruby​​ 中调用 C# dll? - 2

      如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

    3. C# 到 Ruby sha1 base64 编码 - 2

      我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

    4. 基于C#实现简易绘图工具【100010177】 - 2

      C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

    5. ruby - 如何使用 Selenium Webdriver 根据 div 的内容执行操作? - 2

      我有一个使用SeleniumWebdriver和Nokogiri的Ruby应用程序。我想选择一个类,然后对于那个类对应的每个div,我想根据div的内容执行一个Action。例如,我正在解析以下页面:https://www.google.com/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=puppies这是一个搜索结果页面,我正在寻找描述中包含“Adoption”一词的第一个结果。因此机器人应该寻找带有className:"result"的div,对于每个检查它的.descriptiondiv是否包含单词“adoption

    6. ruby-on-rails - 如何处理 Grape 中特定操作的过滤器之前? - 2

      我正在我的Rails项目中安装Grape以构建RESTfulAPI。现在一些端点的操作需要身份验证,而另一些则不需要身份验证。例如,我有users端点,看起来像这样:moduleBackendmoduleV1classUsers现在如您所见,除了password/forget之外的所有操作都需要用户登录/验证。创建一个新的端点也没有意义,比如passwords并且只是删除password/forget从逻辑上讲,这个端点应该与用户资源。问题是Grapebefore过滤器没有像except,only这样的选项,我可以在其中说对某些操作应用过滤器。您通常如何干净利落地处理这种情况?

    7. ruby-on-rails - 在 Ruby on Rails 中发送响应之前如何等待多个异步操作完成? - 2

      在我做的一些网络开发中,我有多个操作开始,比如对外部API的GET请求,我希望它们同时开始,因为一个不依赖另一个的结果。我希望事情能够在后台运行。我找到了concurrent-rubylibrary这似乎运作良好。通过将其混合到您创建的类中,该类的方法具有在后台线程上运行的异步版本。这导致我编写如下代码,其中FirstAsyncWorker和SecondAsyncWorker是我编写的类,我在其中混合了Concurrent::Async模块,并编写了一个名为“work”的方法来发送HTTP请求:defindexop1_result=FirstAsyncWorker.new.async.

    8. ruby - 在 Ruby 中是否有一种惯用的方法来操作 2 个数组? - 2

      a=[3,4,7,8,3]b=[5,3,6,8,3]假设数组长度相同,是否有办法使用each或其他一些惯用方法从两个数组的每个元素中获取结果?不使用计数器?例如获取每个元素的乘积:[15,12,42,64,9](0..a.count-1).eachdo|i|太丑了...ruby1.9.3 最佳答案 使用Array.zip怎么样?:>>a=[3,4,7,8,3]=>[3,4,7,8,3]>>b=[5,3,6,8,3]=>[5,3,6,8,3]>>c=[]=>[]>>a.zip(b)do|i,j|c[[3,5],[4,3],[7,6],

    9. ruby-on-rails - 如何让 Rails View 返回其关联的操作名称? - 2

      我有一个非常简单的Controller来管理我的Rails应用程序中的静态页面:classPagesController我怎样才能让View模板返回它自己的名字,这样我就可以做这样的事情:#pricing.html.erb#-->"Pricing"感谢您的帮助。 最佳答案 4.3RoutingParametersTheparamshashwillalwayscontainthe:controllerand:actionkeys,butyoushouldusethemethodscontroller_nameandaction_nam

    10. arrays - Ruby 数组 += vs 推送 - 2

      我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“

    随机推荐