Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
212 views
in Technique[技术] by (71.8m points)

c# 6.0 - Breaking change in method overload resolution in C# 6 - explanation?

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:

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[])'

Here is the call itself:

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

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.

EDIT

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

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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

I reported it on github here:

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

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

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.

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.

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:

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.

(my emphasis)


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

notice the addition of the two tieBreaker parameters

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...