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

32

我们公司最近从VS2013升级到了VS2017。升级之后,我们的代码库无法再构建。我们得到了以下错误信息:

在'IRepository<T>.Get(object, params Expression<Func<T, object>>[])'和'IRepository<T>.Get(object, params string[])'之间存在二义性

这是调用本身:

this.mainRepository.Get(newEntity.Id);

...以及接口定义:

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

1个回答

39
我在升级到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发表了评论:
所以,新编译器在这方面更加严格,您需要更改您的代码。鉴于AlekseyTs上面的评论,您可能需要考虑将此作为其他案例报告给Microsoft的github。如果这种问题现在在2017年变得更加普遍,因为很多人/公司一直在等待升级,如评论所说,他们可能需要重新评估。此外,您在(旧的)文档中找不到任何关于此的内容的原因是,这是旧编译器的“隐藏功能”,正如他们对文档所做的更改所示: 旧编译器在未使用的参数数组参数存在时实施了特殊的重载解析规则(不在语言规范中),而Roslyn对规范的更严格解释(现已修复)防止了某些程序的编译。
当我们在代码中解决了相同类型的问题后,最终得到了类似这样的结果(以下是使用您的代码的示例):
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);
}

3
谢谢!以下是需要翻译的内容:只是为了参考,这里是Roslyn文档中有关部分的直接链接:https://github.com/dotnet/roslyn/blob/master/docs/compilers/CSharp/Overload%20Resolution.md#tie-breaking-rule-with-unused-param-array-parameters - milosz
1
Eric Lippert关于此主题的观点:https://dev59.com/GWEi5IYBdhLWcg3wwemq#20979453 - GSerg

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