What is the precedence when more than one method overload matches?

I am trying understand OOP concepts in C#.

In the following sample code:

  1. why the ins1 prefers generic method
  2. why the ins2, ins3 prefers non-generic method

Note:when I comment out either of the "MyTestMethod" method, still the program continues to run successfully. This snippet is not something from production. This is just my training sample. So, please do not mind the naming conventions and standards.

using System;

namespace ConsoleApplication1
{
    class Program
    {
        public static void MyTestMethod(J input)
        {
            Console.WriteLine($"Program.MyTestMethod: {input.Val}");
        }
        public static void MyTestMethod<T>(T input) where T : J
        {
            Console.WriteLine($"Program.MyTestMethod<T>: {input.Val}");
        }

        static void Main(string[] args)
        {
            J2 ins1 = new J2(1);
            MyTestMethod(ins1);

            J ins2 = new J(2);
            MyTestMethod(ins2);

            J ins3 = new J2(3);
            MyTestMethod(ins3);

            Console.ReadKey();
        }
    }
    internal class J
    {
        public int Val { get; set; }
        public J(int i)
        {
            Console.WriteLine($"concrete base {i}");
            Val = i;
        }
    }
    internal class J2 : J
    {
        public J2(int i) : base(i * -1)
        {
            Console.WriteLine($"concrete {i}");
        }
    }
}
Jon Skeet
people
quotationmark

Section 7.5.3.2 of the C# specification is the relevant part here - "Better function member".

The result is more simply demonstrated as:

using System;

class Test
{
    static void Foo<T>(T item)
    {
        Console.WriteLine("Generic");
    }

    static void Foo(object x)
    {
        Console.WriteLine("Non-generic");
    }

    static void Main()
    {
        Foo(new object()); // Calls Foo(object)
        Foo("test"); // Calls Foo<T>(T)
    }
}

In both calls, both overloads are applicable function members. In picking which overload to call, the compiler first checks which conversion from argument type (or expression) to parameter type is "better".

When the type of the argument is object, T is inferred to be object as well, and so for both candidates the conversion is the identity conversion of object to object. At that point, the tie-breaking rules of 7.5.3.2 get involved, and the first one is:

If MP is a non-generic method and MQ is a generic method, then MP is better than MQ.

So that's why the non-generic overload is picked in that case.

When the argument is of type string, T is inferred to be string, so we have to compare the conversion from string to string (for the generic method) to the conversion from string to object (for the non-generic method). Here section 7.5.3.3 of the C# spec comes in, which starts:

Given an implicit conversion C1 that converts from an expression E to a type T1, and an implicit conversion C2 that converts from an expression E to a type T2, C1 is a better conversion than C2 if at least one of the following holds:

  • E has a type S and an identity conversion exists from S to T1 but not from S to T2

In this context, E is the expression "test", S is the type string, T1 is the type string, T2 is the type object, and so the conversion from string to string is deemed better - and the generic method is picked.

people

See more on this question at Stackoverflow