Ambiguous method call with overloading Action <T> parameter

I came across some unexpected compiler behavior when calling an overloaded method with various Action<T> variations.

Let's say I have this Test class, and I instantiate it in the CallTest constructor.

 public class Test { public Test(Action<long> arg) { } public Test(Action<decimal> arg) { } } public class CallTest { public CallTest() { Test t = new Test(TestDecimal); } public void TestDecimal(decimal arg) { } public void TestLong(long arg) { } } 

When calling the Test constructor with TestDecimal or TestLong as a parameter, I get the following error:

The call is ambiguous between the following methods or properties: ' Test(System.Action<long>) ' and ' Test(System.Action<decimal>) '

I assume some kind of implicit conversion is taking place between long and decimal , but does anyone have any other idea of ​​what I could have done wrong? Is there a workaround?

+6
source share
3 answers

When you pass TestDecimal or TestLong as a parameter, you are actually passing a group of methods (after all, there may be more than one TestDecimal method - it could be overloaded). Thus, in both cases, an implicit conversion occurs - from a group of methods to a specific type of delegate. Thus, both methods are applicable candidates ( Section 7.4.2 ). Of the applicable candidates, the congestion resolution algorithm tries to find the best candidate. However, the rules for comparing conversions when matching parameter lists are that if for both candidates the implicit conversion is not performed, neither of them is better:

Section 7.4.2.3 :

[...]

Otherwise, conversion is better.

That is why there is ambiguity in your case.


The workaround is, of course, to explicitly specify the parameter:

 new Test(new Action<decimal>(TestDecimal)) 

Thus, for one case, there will be no need for implicit conversion during overload resolution (as after cast Action<T> matches exactly), and the other must be converted ( Action<long> to Action<decimal> ), and the section mentioned above states that:

[...]

If S is T1, C1 is the best conversion.

If S is T2, C2 is the best transformation.

[...]

+6
source

This is due to implicit casting between long and decimal.

Here's a table of implicit castings (for simple types) in C # ( Image Source ):

enter image description here

Read more about type conversions here .

+1
source

There is a workaround:

  Test t = new Test(new Action<decimal>(TestDecimal)); 
+1
source

Source: https://habr.com/ru/post/970230/


All Articles