Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
363 views
in Technique[技术] by (71.8m points)

c# - Overload resolution and virtual methods

Consider the following code (it's a little long, but hopefully you can follow):

class A
{
}

class B : A
{
}

class C
{
    public virtual void Foo(B b)
    {
        Console.WriteLine("base.Foo(B)");
    }
}

class D: C
{
    public override void Foo(B b)
    {
        Console.WriteLine("Foo(B)");
    }

    public void Foo(A a)
    {
        Console.WriteLine("Foo(A)");
    }
}

class Program
{
    public static void Main()
    {
        B b = new B();
        D d = new D ();
        d.Foo(b);
    }
}

If you think the output of this program is "Foo(B)" then you'd be in the same boat as me: completely wrong! In fact, it outputs "Foo(A)"

If I remove the virtual method from the C class, then it works as expected: "Foo(B)" is the output.

Why does the compiler choose the version that takes a A when B is the more-derived class?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The answer is in the C# specification section 7.3 and section 7.5.5.1

I broke down the steps used for choosing the method to invoke.

  • First, the set of all accessible members named N (N=Foo) declared in T (T=class D) and the base types of T (class C) is constructed. Declarations that include an override modifier are excluded from the set (D.Foo(B) is exclude)

    S = { C.Foo(B) ; D.Foo(A) }
    
  • The set of candidate methods for the method invocation is constructed. Starting with the set of methods associated with M, which were found by the previous member lookup, the set is reduced to those methods that are applicable with respect to the argument list AL (AL=B). The set reduction consists of applying the following rules to each method T.N in the set, where T (T=class D) is the type in which the method N (N=Foo) is declared:

    • If N is not applicable with respect to AL (Section 7.4.2.1), then N is removed from the set.

      • C.Foo(B) is applicable with respect to AL
      • D.Foo(A) is applicable with respect to AL

        S = { C.Foo(B) ; D.Foo(A) }
        
    • If N is applicable with respect to AL (Section 7.4.2.1), then all methods declared in a base type of T are removed from the set. C.Foo(B) is removed from the set

          S = { D.Foo(A) }
      

At the end the winner is D.Foo(A).


If the abstract method is removed from C

If the abstract method is removed from C, the initial set is S = { D.Foo(B) ; D.Foo(A) } and the overload resolution rule must be used to select the best function member in that set.

In this case the winner is D.Foo(B).


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...