Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is a generic method chosen when a non-generic exists?

The program below produces this output:

Foo<T> called

Process is terminated due to StackOverflowException.

So, Foo(baz) calls the generic Foo<T>, but Bar(baz) recurses and does not call Bar<T>.

I'm on C# 5.0 and Microsoft .NET. The compiler seems to choose the generic method, instead of recursion, when the non-generic method is an override.

Where can I find an explanation for this rule? (I had guessed that the compiler would choose recursion in both cases.)

Here is the program in its entirety:

using System;

namespace ConsoleApplication1 {
    class Baz { }

    abstract class Parent {
        public abstract void Foo(Baz baz);
    }

    class Child : Parent {
        void Bar<T>(T baz) {
            Console.WriteLine("Bar<T> called");
        }

        public void Bar(Baz baz) {
            Bar(baz);
        }

        void Foo<T>(T baz) {
            Console.WriteLine("Foo<T> called");
        }

        public override void Foo(Baz baz) {
            Foo(baz);
        }
    }

    class Program {
        static void Main(string[] args) {
            var child = new Child();
            child.Foo(null);
            child.Bar(null);
            Console.ReadLine();
        }
    }
}
like image 714
ken Avatar asked Jun 30 '15 21:06

ken


1 Answers

According to the MSDN docs, priority is given to method signatures that are not overridden. Since the non-generic version of Foo is overridden, it immediately goes to the bottom of the priority of choosing a method. In general terms, the next step is to choose the most specific method possible and execute it. In the case of the Bar methods, the Bar(Baz baz) method will always be the most specific in your case.

Overload resolution is a compile-time mechanism for selecting the best function member to invoke given an argument list and a set of candidate function members. Overload resolution selects the function member to invoke in the following distinct contexts within C#:

  • Invocation of a method named in an invocation-expression (Section 7.5.5). Invocation of an instance constructor named in an object-creation-expression (Section 7.5.10.1).
  • Invocation of an indexer accessor through an element-access (Section 7.5.6). Invocation of a predefined or user-defined operator referenced in an expression (Section 7.2.3 and Section 7.2.4).

Each of these contexts defines the set of candidate function members and the list of arguments in its own unique way, as described in detail in the sections listed above. For example, the set of candidates for a method invocation does not include methods marked override (Section 7.3), and methods in a base class are not candidates if any method in a derived class is applicable (Section 7.5.5.1).

MSDN Overload Resolution

I bolded the text that I think relates to your question.

Here's another question on Stack Overflow that might help out. It talks about method resolution in general. Doesn't touch on overridden methods, but helps fill in some of the process that I didn't touch on.

like image 121
Nathan Avatar answered Oct 04 '22 02:10

Nathan