28

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?

Community
  • 1
  • 1
Parashuram
  • 1,498
  • 2
  • 16
  • 36
  • Similar to [this question](http://stackoverflow.com/questions/9017363/ambiguous-method-overloading) – adelphus Oct 01 '15 at 17:10

4 Answers4

47

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.

Erik
  • 5,355
  • 25
  • 39
  • Is there an up-to-date link for the specification? – derHugo Jul 07 '22 at 07:57
  • Here: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/readme Looks like section numbers have changed, I haven't looked yet to find where they talk about overload resolution. – Erik Jul 14 '22 at 01:03
  • Thanks! I've found [7.6 Signatures and overloading](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/basic-concepts#76-signatures-and-overloading) but I couldn't find yet the specification of which overload will be preferred - I mean you basically said it but how do I know what is `more specific` thinking e.g. also in interfaces and generic etc – derHugo Jul 14 '22 at 07:10
12

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.

Vlad274
  • 6,514
  • 2
  • 32
  • 44
1

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.

0

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