Why is this method invocation ambiguous? - c#

Why does the first call to Foo below compile but the second one results in an ambiguous invocation compiler error?
(using c# 7.2)
private static void AmbiguousAsyncOverload() {
Foo(() => Bar()); // This is OK
//Foo(Bar); // Error, ambiguous overload
}
private static void Foo(Func<int> func) {
func();
}
private static void Foo(Func<string> func) {
func();
}
private static int Bar() {
return 4;
}
If I remove the first (Func<int>) implementation of Foo, and hence the possibility of ambiguity, then the compiler (correctly) reports that Bar doesn't have the correct signature to be passed into Foo, which implies it has enough information to resolve the ambiguity.
I would understand if the compiler didn't look at return values during overload resolution and therefore both calls failed, but my question is why does one call compile ok while the other doesn't.

This was an issue for all versions of C# up until it was fixed in v7.3. Return types were not taken into account during overload resolution. From the release notes (or the language proposal) for C# 7.3:
For a method group conversion, candidate methods whose return type doesn't match up with the delegate's return type are removed from the set.

Related

Which C# method overload is chosen?

Why is the generic method called when both overloads would match?
public static void method1(object obj)
{
Console.WriteLine("Object");
}
public static void method1<T>(T t)
{
Console.WriteLine("Type T");
}
public static void Main(String args[])
{
method1("xyz"); //Will print "Type T";
}
There should not be any conflicts here, right?
Overloads are resolved by choosing the most specific overload. In this case, method1<string>(string) is more specific than method1(object) so that is the overload chosen.
There are details in section 7.4.2 of the C# specification.
If you want to select a specific overload, you can do so by explicitly casting the parameters to the types that you want. The following will call the method1(object) overload instead of the generic one:
method1((object)"xyz");
There are cases where the compiler won't know which overload to select, for example:
void method2(string x, object y);
void method2(object x, string y);
method2("xyz", "abc");
In this case the compiler doesn't know which overload to pick, because neither overload is clearly better than the other (it doesn't know which string to implicitly downcast to object). So it will emit a compiler error.
C# will always choose the most specific method it can.
When compiling
method1("xyz");
it will look for all methods with the specified name and then attempt to match parameters. The compiler will choose the method that is the most specific, in this case it would prefer
method1(string s)
over
method1<T>(T t) with T = string
and lastly
method1(object o)
Please note #Erik's excellent answer for an example where the compiler fails to decide.
Because you are already passing in T as a parameter so you don't need to type out method1<string>("xyz");you can just go method1("xyz");, .Net already knows it's a string. If you had method1 then it would be a different story.
Also since method1(object obj) doesn't take in a string as parameter it will favor the generic function first where it can infer T. If you were to change method1(object obj) to method1(string obj) it would favor it first then the generic.
How method overloading works
To find the matching signature of a method for a call, the compiler search in the type hierarchy from bottom to top as well in virtual table:
First in the class hierarchy,
Then in the interface hierarchy.
Because classes prevail on interfaces.
Indeed, before being of type of an interface, an object is of type of a class first of all.
And non generic signatures prevail over generic as reality and facts prevail over abstraction, unless using the generic parameter allow a call on the more specialized type of instance.
Applying the theory to the question
This call:
method1("xyz");
Match perfectly with:
void method1<T>(T t) { }
Before matching with:
void method1(object obj)
Because string is a specialized object and it can be used as a generic parameter to be more acurate.
On the other side, if you write:
void method1(string obj) { }
void method1<T>(T t) { }
The first method is so called.
Case study
var instance = new List<string>();
MyMethod(instance);
MyMethod((IEnumerable<string>) instance);
MyMethod<string>(instance);
MyMethod((object)instance);
void MyMethod<T>(List<T> instance) { }
void MyMethod<T>(IEnumerable<T> list) { }
void MyMethod<T>(T instance) { }
void MyMethod(object instance) { }
The first call calls the first method because instance is type of List (type matching).
The second call calls the second method because of the side cast (implementation).
The third call calls the third method because of the generic parameter specified to act on (templating).
The fourth call calls the fourth method because of the down cast (polymorphism).

type argument from Action<T> cannot be inferred, but from Func<T> can be

I've been playing a little with generics and delegates and I have found something I don't understand. I have quite similar generic static methods, one accepts Action<T> and the second one accepts Func<T>. Now the problem: if I call the one accepting Func<T> without explicit Type, compiler is fine with that. But with the one accepting Action<T> my program can't be compiled (see the code for error message).
My question is: Why is compiler able to recognize return type, but is not able to recognize argument type?
public interface IMessage
{ }
public class Message : IMessage
{
}
static void HandleAction<TMessage>(Action<TMessage> action)
where TMessage : IMessage
{ }
static void HandleFunction<TMessage>(Func<TMessage> action)
where TMessage : IMessage
{ }
static void A(Message message)
{ }
static Message F()
{
return new Message();
}
static void Main(string[] args)
{
// this one is ok
HandleFunction(F);
// compiler error:
// The type arguments for method
// 'template_test.Program.HandleAction<TMessage>(System.Action<TMessage>)'
// cannot be inferred from the usage.
//Try specifying the type arguments explicitly.
//HandleAction(A);
// this one is ok
HandleAction<Message>(A);
}
I'm using .NET 4.5 in Visual Studio 2012.
Methods can be overloaded by their arguments and all overloads form one method group, so for example void Xyz(int i) and void Xyz(string s) are within same method group called Xyz. Compiler is not able to deduct a type of argument even if user defines only one method, because behaviour of compiler is quite strict.
Methods can't be overloaded by return types, so you can't have int Xyz() and string Xyz() within same class. Return type can be deducted by compiler easily, because there is no overloading.
It was not obvious for me for the first time, but it has been quite clear after I realized that I could create an overload.

overloading with generics. Is it expected behaviour? [duplicate]

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
A problem with generic method overloading
Here is a simple code:
static class Example
{
static int DoIt(object o) { return 0; }
class A { }
static int DoIt(A a) { return 1; }
static int CallDoIt<X>(X x) { return DoIt(x); }
static void Main()
{
var a = new A();
System.Console.WriteLine(DoIt(a)); // returns 1 (as desired)
System.Console.WriteLine(CallDoIt(a)); // returns 0
}
}
The result looks very strange: the function DoIt() called directly returns different value from the case when it is called from another function. Is it expected behaviour in C#? If yes, how to achieve the desired behaviour (preferably without reflection)?
This is the expected behaviour, the knowledge of what type X is does not extend into the CallDoIt function. The overload of DoIt called from CallDoIt is determined statically based on the type of the argument x. Since X can be anything, the best (and only) candidate is DoIt(object).
You can get around this behaviour by delaying the dispatch to DoIt until runtime using dynamic:
static int CallDoIt<X>(X x) { return DoIt((dynamic)x); }
The other alternative is to provide a more specific version of CallDoIt:
static int CallDoIt(A a) { return DoIt(a); }
Method call DoIt(x) inside method CallDoIt<X>(X x) must work for any X type, so C# compiler chose to use DoIt(object o) overload.
If you restrict X type to derive from type A like this:
static int CallDoIt<X>(X x) where X : A { return DoIt(x); }
Then C# compiler will know it can chose DoIt(A a) overload since X type will always derive from type A. This also answers your second question of how to achieve the desired behaviour.
Yes, that is the expected behaviour. A generic method is compiled once for all possible arguments. During that single compilation, DoIt(x) cannot be resolved to DoIt(A), so it is DoIt(object), and that is what it will always be.
You can dynamically check the object type, or better yet, have .NET Framework do so for you:
static int CallDoIt(object x) { return DoIt((dynamic)x); }
Note that there is no benefit here to making CallDoIt generic: it would do exactly the same as this version. That means that CallDoIt((object)a) calls DoIt(A), not DoIt(object).
Add another overload for CallDoIt:
static int CallDoIt(A x) { return DoIt(x); }
This will make things work.
The overload resolution occurs at compile time (if no dynamic resolution needed) and most specific type for X(type parameter) is object.
The decision of choose calling method will be resolved at compile time. The C# compiler does not know what is the type X and choosed the method with DoIt(object o).

Both Action and Func<T> without explicit casting

I have a class that has to receive methods in order to call them as well as doing other executions. These methods have to be used many times and for many different users so the simpler the better.
To deal with this I have two methods:
void Receive(Action func)
{
// Do some things.
func();
}
T Receive<T>(Func<T> func)
{
// Do some things.
return func();
}
(Actually I have 34 methods to be able to receive any of the different Action or Func defined.)
Then, I want to be able to pass any method as a parameter to the Receive function, to be able to do something like this:
void Test()
{
Receive(A);
Receive(B);
}
void A()
{
}
int B()
{
return 0;
}
Just like this, it gives me one error in Receive(B):
The call is ambiguous between the following methods or properties: 'Class1.Receive(System.Action)' and 'Class1.Receive<int>(System.Func<int>)'
Ok, the signature is the same (although no error is shown if I don't use the methods).
If I remove the Receive(Action) method, I get in Receive(A) the following error:
The type arguments for method 'Class1.Receive<T>(System.Func<T>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
But my type in this case is void and it is forbidden to use it as a generic parameter.
So, is there a way to have my Receive method without using any explicit cast of Action or Func?
No you can't do this - void is not a valid return type for Func<T>. The best you could do is to wrap it in a Func<object>:
Receive(() => { A(); return null; });
Try specifying the generic type parameter explicitly:
Receive<int>(B);

Method overloading in generic class

I am working with a code that contains following overloaded method in generic class:
public class A<T>
{
public void Process(T item) { /*impl*/ }
public void Process(string item) { /*impl*/ }
}
When parametrizing the class for string do I lose the possibility to call the version with generic parameter?
var a = new A<string>();
a.Process(""); //Always calls the non-generic Process(string)
Specific types take precedence over generic types.
For example, this is what I tested with in LINQPad.
void Main()
{
new A<string>().Process("Hello");
}
public class A<T>
{
public void Process(T item) { Console.WriteLine("T"); }
public void Process(string item) { Console.WriteLine("string"); }
}
// Output: string
If you have a problem with hiding the generic method, then you need to rethink something. By overloading a generic method with specific types, you are effectively saying, "Use the generic overload if you need to, but if you can, use the specific version, because it should know what is best."
There is one way I just discovered, but it's a bit cross-eyed. Because generics and overloading get resolved in build time, you can define a generic method:
public static CallerClass
{
public static CallGenericOverload<T>(GenericClass<T> cls, T val)
{
return cls.ProblemOverload(val);
}
//We can also make an extension method.
//We don't have to of course, it's just more comfortable this way.
public static CallGenericOverloadExtension<T>(this GenericClass<T> cls, T val)
{
return cls.ProblemOverload(val);
}
}
public GenericClass<T>
{
public string ProblemOverload(T val)
{
return "ProblemOverload(T val)";
}
public string ProblemOverload(string val)
{
return "ProblemOverload(string val)";
}
}
Now, if we do the following:
var genClass = new GenericClass<string>();
Console.WriteLine(genClass.ProblemOverload("")); //output: ProblemOverload(string val)
Console.WriteLine(CallerClass.CallGenericOverload(genClass, "")); //output: ProblemOverload(T val)
Console.WriteLine(genClass.CallGenericOverloadExtension("")); //output: ProblemOverload(T val)
You can use a similar trick if you define a generic class instead of a generic method. The important thing is that the parameter you transfer to ProblemOverload needs to be of type T rather than type string in the invocation. After all, the method CallGenericOverload knows it's getting a T at build time, so it's going to bind to the overload that accepts the parameter. It doesn't matter that it's actually going to get a string at runtime.
Yes. This is documented in the C# spec, section 7.5.3, overload resolution.
From 7.5.3.6:
"While signatures as declared must be unique, it is possible that substitution of type arguments results in identical signatures. In
such cases, the tie-breaking rules of overload resolution above will
pick the most specific member."
The example given in there states that in the case below, overload resolution for G<int>.F1 will pick non-generic
class G1<U>
{
int F1(U u);
int F1(int i);
}
The tie-breaking rule that applies here is outlined in 7.5.3.2, "Better function member":
In case the parameter type sequences {P1, P2, …, PN} and {Q1, Q2, …,
QN} are equivalent (i.e. each Pi has an identity conversion to the
corresponding Qi), the following tie-breaking rules are applied, in
order, to determine the better function member.
If MP is a non-generic method and MQ is a generic method, then MP is better than MQ.
Having done this before, I'm inclined to say "No," but there's always more knowledgable folks who would argue otherwise.
If memory serves, the runtime compiler chooses the most strongly typed overload to execute.
CLARIFICATION
My answer is badly worded, and I deserve the downvote.
The OP asked, "When parametrizing the class for string do I lose the possibility to call the version with generic parameter?" I wasn't answering that "No, you can't do that," but that "No, you don't lose the ability to call the version with the generic parameter."
I should have been more clear.

Categories

Resources