C#6中方法重载分辨率的重大更改-解释吗? [英] Breaking change in method overload resolution in C# 6 - explanation?

查看:76
本文介绍了C#6中方法重载分辨率的重大更改-解释吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

We've recently moved from VS2013 to VS2017 in our company. After the upgrade our codebase would no longer build. We would get the following error:


以下方法或属性之间的调用不明确:'IRepository< T> .Get(object, params Expression< Func< T,object >> [])'和'IRepository< T> .Get(object,params string [])'

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);

...以及接口定义:

...and the interface definition:

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的新的改进的方法重载分辨率功能,但是从语言规范来看,我无法找到导致该问题的确切规则。

I was wondering if anyone here could explain why this is the case. I suspect the new Improved method overload resolution feature of C# 6.0 but looking at the language spec I wasn't able to find out the exact rule responsible for the issue.

编辑

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

I wrote a follow-up blog post about this problem: http://codewithstyle.info/method-overload-resolution-in-c-6-0-an-interesting-bug-story

推荐答案

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

I discovered the same thing when upgrading to Visual Studio 2015 so this is not new with 2017, but it is new since 2013.

我在github上进行了报道:

I reported it on github here:

在VS2013中编译的代码在2015年因CS0121而失败;参数类型为#4458的具有不同params参数的重载:

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

问题是代码不确定并且新的Roslyn编译器更严格

The problem is that the code is ambiguous and the new Roslyn compiler is stricter on this than the previous compiler.

作为问题向 Overload Resolution.md#4922 添加有关#4458的信息。

The issue was closed with an action to change the documentation instead of reverting to the old behavior, as part of issue Add information about #4458 to "Overload Resolution.md" #4922.

特别是 AlekseyTs 对此进行了评论:

In particular, AlekseyTs commented this:


为了我们的重载解决方案代码的未来健康,我们决定保留中断(且正确)的行为。如果我们得到的不仅仅是单个案例,我们可能需要重新评估。

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.

因此,您有了它。新的编译器对此要求更高,您需要更改代码

So there you have it. The new compiler is stricter on this and you need to change your code.

鉴于AlekseyTs的上述评论,您可能想考虑将此问题报告给github上的Microsoft,作为其他此类情况。如果这种问题在2017年末之前变得越来越普遍,因为很多人/公司都在等待升级,正如评论说他们可能想重新评估。

Given the comment above by AlekseyTs, you might want to consider reporting this to Microsoft on github as an additional such case. If this kind of problem is becoming more widespread now that 2017 is out, because a lot of people/companies have waited with upgrading, as the comment say they may want to reevaluate.

此外,在(较旧的)文档中找不到任何相关内容的原因是,这是较旧的编译器的隐藏功能,如将其更改为文档

In addition, the reason why you don't find anything in the (older) documentation about this is that this was a "hidden feature" of the older compiler, as evident from the change they did to the documentation:


旧编译器为重载解析实施了特殊规则(不在语言规范中)在存在未使用的参数数组参数的情况下,并且Roslyn对规范的更严格解释(现已修订)阻止了某些程序的编译。

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.

(我的重点)

当我们在代码中解决了相同类型的问题时,我们最终得到了这样的内容(使用您的代码的示例):

When we fixed the same type of problem in our code we ended up with something like this (example using your code):

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的加法参数

然后,我们将显式参数包含在集合中,并将其他参数包含在内。如果您需要不使用这些可选的额外参数来调用该方法,则应添加第三个重载,该重载没有明确说明应调用哪个重载,因此您的最终接口可能如下所示:

Then we just included the explicit parameter into the collection with the others inside. If you need to be able to call the method with none of those optional extra parameters you should add a 3rd overload that doesn't have them to be explicit about which overload should be called so your final interface might look like this:

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#6中方法重载分辨率的重大更改-解释吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆