C# overload with override

2019-03-04 17:27发布

问题:

I can surely answer to this question by myself writing a dummy test but I want to know what people think about the question. Here it is:

Which method will be call when we have both at the same time overloading and overriding? I am only considering Type overloading and not arity overloading and when Type the overload are related.

Let me throw you an example:

class AA {}
class BB : AA {}

class A {
    public virtual void methodA(AA anAA) { Console.Write("A:methodA(AA) called"); }
    public virtual void methodA(BB aBB) { Console.Write("A:methodA(BB) called"); }
}

class B : A {
    public override void methodA(AA anAA) { Console.Write("B:methodA(AA) called"); }
}

new B().methodA(new BB());     // Case 1
new B().methodA(new AA());     // Case 2
new B().methodA((AA)new BB()); // Case 3

Can you tell what will happen in case 1, 2, and 3?

I personally think that overloadaing is evil and that there is no consistent thinking that could lead to a predictable answer. And that is completely base on a convention implemented in the compiler+vm.

EDIT: If you have some doubt about why overload is evil you can read the blog post from Gilad Brach

Thanks

回答1:

Overridden methods are excluded from method set when compiler determines which method to call. See member lookup algorithm. So, when you call methodA on type B, set of members with name methodA from type B and it's base type will be constructed:

override B.methodA(AA)
virtual A.methodA(AA)
virtual A.methodA(BB)

Then members with ovveride modifier removed from set:

virtual A.methodA(AA)
virtual A.methodA(BB)

This group of methods is the result of lookup. After that overload resolution applied to define which member to invoke.

  1. A.methodA(BB) is invoked, because its argument matches parameter.
  2. A.methodA(AA) will be chosen, but it is virtual method, so actually call goes to B.method(AA)
  3. Same as option 2


回答2:

No, it is entirely predictable. The method signature is resolved first - that is, the overload is determined first. Then, the most overridden method is called. So the output will be:

  • A:methodA(BB) called
  • B:methodA(AA) called
  • B:methodA(AA) called

The method taking an instance of AA will be called in the second two cases, because this is the type of the reference that is passed in, and it is B's version that is called. Note that even this would produce the same result:

A instance = new B();
instance.methodA((AA)new BB()); // Case 3


回答3:

I think the result will be this

case 1 : Console.Write("A:methodA(BB) called");

case 2 : Console.Write("B:methodA(AA) called");

case 3 : Console.Write("B:methodA(AA) called");

in case 3 it will look the type that it's passed, and it's B