重载方法未找到。

4
安装如下:
  • 一个 .NET Standard 2.0 库
  • 一个 NUnit 测试项目,目标为 .NETFramework 4.6.1

使用最新的 VS 2017 和 NUnit。

我在周末在家里工作,并将我的工作上传到 git,今天开始从公司工作(我之前已经在两个地方都工作过)。只有现在我发现项目出了问题(我不太记得一开始是什么问题,但似乎问题与我现在遇到的问题相同,稍后会描述)。

在试图修复它的过程中,我把它弄得无法修复了,于是我完全删除了它,并重新克隆了 git 库。

该项目编译良好,但运行时测试抛出“方法未找到”异常。稍微调查了一下,发现问题仅表现在以下方法的一个重载上:

    public static YNABClient GetInstance(HttpMessageHandler _handler)
    {
        if (instance is null)
        {
            instance = new YNABClient(_handler);
        }

        return instance;
    }

    public static YNABClient GetInstance() => GetInstance(new HttpClientHandler());

没有参数的那个没问题,有参数的出了点问题。尝试删除和添加测试库的引用,删除和添加测试和库项目。我在网上找到的其他类似情况的解决方案都是针对ASP.NET MVC的,但这并不是我的情况,虽然这个问题让我检查了重载,并发现其中一个确实有效。
在家里一切正常,虽然我还没有像在工作中那样尝试删除和重新安装项目。这导致问题可能有两个来源:环境,尽管我还没有找到有意义的区别,或者git,尽管我使用VS的“标准”git忽略(这个),所以那里不应该有问题。我的项目基本设置在周末之前没有改变并且正常工作,所以最近的更改肯定是导致了某些问题。
此外,如果我向解决方案添加控制台应用程序(.NET Framework 4.6.1),并尝试从中调用有问题的方法,则其实际上可以正常工作。
如果需要,我的GitHub项目链接在这里
在评论中有人要求提供调用示例。基本上,我有两个不同设置的测试夹具类——一个用于实际调用API以便于调试实际使用,另一个则为其提供虚拟数据,符合良好的测试实践。以下为正常的工作示例:
    [OneTimeSetUp]
    public void Setup()
    {
        ynabClient = YNABClient.GetInstance();
        ynabClient.RefreshAccessToken(ApiKeys.AccessToken);
    }

抛出异常:

    [OneTimeSetUp]
    public void Setup()
    {
        handler = new StubHandler();
        ynabClient = YNABClient.GetInstance(handler);
    }

一些调查表明,我的问题很可能与.NET Framework和.NET Standard的System.Net.Http版本不一致有关,如果您在谷歌上搜索,这是一个非常普遍的问题。然而,我找到的所有示例都没有展示出我的特定症状,我还不确定该怎么办。为什么在我家里的电脑上一切都正常呢?

由于问题仅在运行时发生,您需要使用反射(或使用dynamic)发布调用“GetInstance”方法的位置。由于某种原因,运行时绑定器无法将参数与静态方法匹配起来。 - D Stanley
正如我所说,我是从 NUnit 测试项目中调用它的。它是公共的,不需要反射。虽然我不知道 NUnit 在内部是如何工作的,但一切都非常简单明了。我会添加示例。 - Misamoto
当我运行你的测试时,所有的模拟测试都通过了,但是真正的测试都失败了:“YNAB没有授权我们。访问令牌没问题吗?”听起来像是你的模拟测试失败了,而我无法使用你的代码进行复现。请尝试将其简化为一个最小可重现示例(MCVE)。 - Jon Skeet
你的尝试实际上验证了问题出在环境上。所有测试都按照预期进行 - 模拟通过,因为它们没有外部依赖项,而真实的测试返回未经授权的异常,因为你没有提供访问密钥。 - Misamoto
不,我没有版本问题。版本歧义是编译时错误。我可以通过从Nuget安装库的不同版本(而不是使用框架中的版本)来“手动”引起它,然后解决方案根本无法编译。但它对于重载的方法没有任何作用。 - Misamoto
显示剩余5条评论
3个回答

0
你遇到的问题是你的GetInstance方法接受HttpMessageHandler作为参数,而在你的test中你传递了HttpClientHandler对象。因此,你声明了一个参数,但在调用该方法时提供了不同的对象。

0

我在我的环境中遇到了这个错误:

严重性 代码 描述 项目 文件 行 抑制状态 错误 CS0433 类型 'HttpMessageHandler' 在两个程序集中都存在 'System.Net.Http, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' 和 'System.Net.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'

您的 YNABConnector 是 .NET Standard 2,但 Unit test 是 4.6.1,它们为同一程序集使用不同的签名。

这里是官方文档以供测试: https://github.com/nunit/docs/wiki/.NET-Core-and-.NET-Standard

  1. 创建一个 .NET Core 库(请注意:不能是上述链接中的 .NET Standard 库),
  2. 将您的测试代码复制到其中,
  3. 按照官方文档添加引用,

如果您的代码可以正常工作,则没有错误。

但是在你的基础代码中,我仍然更喜欢这段代码:

public class YNABClient
{
    private static YNABClient instance;

    private HttpClient client;

    private HttpMessageHandler handler;

    private YNABClient(HttpMessageHandler _handler = null)
    {
        handler = _handler ?? new HttpClientHandler();
        client = new HttpClient(_handler);
    }

    public static YNABClient GetInstance(HttpMessageHandler _handler = null)
    {
        return instance ?? (instance = new YNABClient(_handler));
    }

    ......
}

HttpMessageHandler是一个抽象类。HttpClientHandler是它的默认值。在测试期间,为了交换依赖项,需要使用另一个处理程序来实例化客户端 - 我们不想在测试解析器时实际上将任何内容发布到真实服务器。虽然这是我未来可能想要处理的次优实现,但现在这正是预期的。再次阅读问题 - 该方法的无参数版本实际上是有效的。 - Misamoto
好吧,现在离题了,但是看一下StubHandler以及它在测试库中的使用,就能理解为什么参数被声明成这样。对我来说,消除重载太过于粗暴了。你知道,没有理由让它们不起作用,这只是一个需要解决的错误。正如Daisy Shipton在评论中所证明的那样,因为他的所有东西都可以工作。 - Misamoto
是因为你的框架吗?你的 YNABConnector 是 .NET Standard 2.0,但你的 UnitTest 是 4.6.1? - Dongdong

0

所以,正如DongDong建议的那样,问题确实出在.NET Framework和.NET Standard之间的接口。问题并不是它们不兼容,或者Test项目需要一些额外的依赖项,而是它们使用了不同版本的System.Net.Http。

诊断过程被阻碍了,因为没有显示任何可见错误。但是,更改参数类型表明,问题确实只存在于该命名空间中的类。

诊断问题的另一个问题是,该项目在某些机器上运行良好(我家里的PC和评论中的Daisy Shipton的机器)。

然而,在确定问题的来源后,我能够通过谷歌找到了该库一开始存在的不兼容性问题,最终在.NET github上发现了一堆不兼容性问题。

我尝试了那些情况下使用的解决方案,并向库的具体版本添加了“绑定重定向”,之后它就可以正常工作了。 我将重定向添加到我的Tests项目的app.config中。参考代码如下:

<dependentAssembly>
    <assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
    <bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
</dependentAssembly>

我仍然不明白为什么这个项目在某些机器上运行良好。


.NET Standard 2比4.6.1更新,应该具有在旧版本中无法工作的新功能。但我应该得到你的赞! - Dongdong
你做到了 :) 你也被某人踩了,所以得分是0。另一个答案更值得得分,但是...此外,根据文档 https://learn.microsoft.com/en-us/dotnet/standard/net-standard ,.Net Standard 应该与4.6.1完全兼容,所以新旧版本无关 :) - Misamoto

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