Why is method overloading not working in this C# p

2019-06-25 14:36发布

问题:

namespace test
{
    class Program
    {

        static void Main(string[] args)
        {
            Derived obj = new Derived();
            int i = 10;
            obj.Foo(i);

            Console.ReadLine();
        }

    }
    class Base
    {
        public virtual void  Foo(int i)
        {
            Console.WriteLine("Base:Foo()");
        }
    }
    class Derived:Base
    {
        public override void Foo(int i)
        {
            Console.WriteLine("Foo(int)");
        }
        public void Foo(object i)
        {
            Console.WriteLine("Foo(object)");
        }
    }
}

output of the program according to me should be Foo(int) but output is coming as Foo(object) please help me in understanding the diffrence in output

回答1:

Good question, I can reproduce your results. If one takes a look at the C# specifications one will find the following snippets:

7.5.3 Overload resolution

For example, the set of candidates for a method invocation does not include methods marked override (§7.4), and methods in a base class are not candidates if any method in a derived class is applicable (§7.6.5.1).

7.4 Member Lookup

Otherwise, the set consists of all accessible (§3.5) members named N in T, including inherited members and the accessible members named N in object. If T is a constructed type, the set of members is obtained by substituting type arguments as described in §10.3.2. Members that include an override modifier are excluded from the set.

7.6.5.1 Method invocations

The set of candidate methods is reduced to contain only methods from the most derived types: For each method C.F in the set, where C is the type in which the method F is declared, all methods declared in a base type of C are removed from the set. Furthermore, if C is a class type other than object, all methods declared in an interface type are removed from the set.

Sounds a bit complicated? Even the C# designers seem to think so and put in the 'helpful' note:

7.6.5.1 Method invocations

The intuitive effect of the resolution rules described above is as follows: To locate the particular method invoked by a method invocation, start with the type indicated by the method invocation and proceed up the inheritance chain until at least one applicable, accessible, non-override method declaration is found. Then perform type inference and overload resolution on the set of applicable, accessible, non-override methods declared in that type and invoke the method thus selected. If no method was found, try instead to process the invocation as an extension method invocation.

If we take a look at your derived class, we see two possible methods for C# to use:

 A) public override void Foo(int i) 
 B) public void Foo(object i)

Let's use that last checklist!

Applicability - Both A and B are applicable -(both are void, both are named 'Foo' and both can accept an integer value). Accessibility - Both A and B are accessible (public) Not Overridden - Only B is not overridden.

But wait you might say! A is more specific than B!

Correct, but that consideration is only made after we've disregarded option A. As Eric Lippert (one of the designers) puts it Closer is always better than farther away. (Thanks Anthony Pegram)

Addendum

There is always the 'new' keyword:

class Derived : Base
{
    public new void Foo(int i)
    {
        Console.WriteLine("Foo(int)");
    }

    public void Foo(object i)
    {
        Console.WriteLine("Foo(object)");
    }
}

Though the specifics of that best left for another question!



回答2:

The simple datatype int descends from object. You are overriding the function and also overloading the parameter list. Since the function name is the same with a different signature the compiler allows this. For simple objects, I image one copy of the parameter signature in the most basic form is stored in the method table.