c# - C# 6 中方法重载解析的重大变化 - 解释?

标签 c# c#-6.0 overload-resolution

我们公司最近从 VS2013 迁移到 VS2017。升级后我们的代码库将不再构建。我们会得到以下错误:

The call is ambiguous between the following methods or properties: 'IRepository<T>.Get(object, params Expression<Func<T, object>>[])' and 'IRepository<T>.Get(object, params string[])'

这是调用本身:

this.mainRepository.Get(newEntity.Id);

...以及接口(interface)定义:

public interface IRepository<T> where T : class
{
    T Get(object id, params Expression<Func<T, object>>[] includeExprs);
    T Get(object id, params string[] includeExprs);
}

我想知道这里是否有人可以解释为什么会出现这种情况。我怀疑 C# 6.0 的新改进的方法重载解析功能,但查看语言规范,我无法找出导致该问题的确切规则。

编辑

我写了一篇关于这个问题的后续博客文章:http://codewithstyle.info/method-overload-resolution-in-c-6-0-an-interesting-bug-story

最佳答案

我在升级到 Visual Studio 2015 时发现了同样的事情,所以这对于 2017 年来说并不是什么新鲜事,但它是自 2013 年以来的新内容。

我在 github 上报告了它:

Code that compiles in VS2013 fails with CS0121 in 2015; overloads with different params parameter types #4458 :

问题在于代码不明确,并且新的 Roslyn 编译器对此比以前的编译器更严格。

作为问题 Add information about #4458 to "Overload Resolution.md" #4922 的一部分,通过更改文档而不是恢复到旧行为的操作解决了该问题.

特别是,AlekseyTs对此发表评论:

In the interest of the future health of our overload resolution code, we decided to keep the breaking (and correct) behavior. If we get more than this single case, we may want to reevaluate.

所以你已经得到它了。新的编译器对此更加严格,您需要更改代码

鉴于 AlekseyTs 的上述评论,您可能考虑在 github 上向 Microsoft 报告此情况,作为另一个此类案例。如果现在2017年已经过去了,这种问题变得更加普遍,因为很多人/公司都在等待升级,正如评论所说,他们可能想重新评估。

此外,您在(较旧的)文档中找不到任何有关此内容的原因是,这是旧编译器的“隐藏功能”,如 change they did to the documentation 所示。 :

The old compiler implemented special rules for overload resolution (not in the language specification) in the presence of unused param-array parameters, and Roslyn's more strict interpretation of the specification (now fixed) prevented some programs from compiling.

(我的重点)

<小时/>

当我们在代码中修复相同类型的问题时,我们最终得到了类似的结果(使用您的代码的示例):

public interface IRepository<T> where T : class
{
    T Get(object id, Expression<Func<T, object>>[] tieBreaker, params Expression<Func<T, object>>[] includeExprs);
    T Get(object id, string tieBreaker, params string[] includeExprs);
}

注意添加了两个 tieBreaker 参数

然后我们将显式参数与其他参数一起包含到集合中。如果您需要能够在不使用任何可选额外参数的情况下调用该方法,您应该添加第三个重载,该重载不明确应调用哪个重载,因此您的最终界面可能如下所示:

public interface IRepository<T> where T : class
{
    T Get(object id);
    T Get(object id, Expression<Func<T, object>>[] tieBreaker, params Expression<Func<T, object>>[] includeExprs);
    T Get(object id, string tieBreaker, params string[] includeExprs);
}

关于c# - C# 6 中方法重载解析的重大变化 - 解释?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59613641/

相关文章:

c# - MVVM 选项卡 : Focus new tab

c# - 使用字符串插值将字符串转换为大写

c# - 如何在 Visual Studio 2015 中更改语言版本

c++ - 不同编译器使用的不同类型转换运算符

c# - 如何以编程方式卸载 Windows 中的应用程序?

c# - 如何在C#中查找char数组中的字符索引

c# Access System.Data.OleDb.OleDbException (0x80040E14) : Syntax error in UPDATE statement

c# - 使用 async 和 await 回调

c++ - 从构造函数内 - 有条件地调用成员变量的构造函数重载

delphi - DrawText 重载解析错误