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
241 views
in Technique[技术] by (71.8m points)

c# - Will CLR check the whole inheritance chain to determine which virtual method to call?

The inheritance chain is as follows:

class A
    {
        public virtual void Foo()
        {
            Console.WriteLine("A's method");
        }
    }

class B:A
    {
        public override void Foo()
        {
            Console.WriteLine("B's method");
        }
    }

class C:B
    {
        public new virtual void Foo()
        {
            Console.WriteLine("C's method");
        }
    }

class D:C
    {
        public override void Foo()
        {
            Console.WriteLine("D's method");
        }
    }

then:

class Program
    {
        static void Main(string[] args)
        {
            A tan = new D();
            tan.Foo();
            Console.Read();
        }
    }

The result is, the method foo() in class B is called.

But in the reference:

When a virtual method is invoked, the run-time type of the object is checked for an overriding member. The overriding member in the most derived class is called, which might be the original member, if no derived class has overridden the member.

In my logic, CLR first finds Foo() is a virtual method, it looks into the method table of D, the runtime type, then it finds out there is an overriding member in this most derived class, it should call it and never realizes there is a new Foo() in the inheritance chain.

What's wrong with my logic?

See Question&Answers more detail:os

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

1 Reply

0 votes
by (71.8m points)

Amy's answer is correct. Here's how I like to look at this question.

A virtual method is a slot that can contain a method.

When asked to do overload resolution, the compiler determines which slot to use at compile time. But the runtime determines what method is actually in that slot.

Now with that in mind let's look at your example.

  • A has one slot for Foo.
  • B has one slot for Foo, inherited from A.
  • C has two slots for Foo. One inherited from B, and one new. You said you wanted a new slot named Foo, so you got it.
  • D has two slots for Foo, inherited from C.

That's the slots. So, what goes in those slots?

  • In an A, A.Foo goes in the slot.
  • In a B, B.Foo goes in the slot.
  • In a C, B.Foo goes in the first slot and C.Foo goes in the second slot. Remember, these slots are completely different. You said you wanted two slots with the same name, so that's what you got. If that's confusing, that's your problem. Don't do that if it hurts when you do it.
  • In a D, B.Foo goes in the first slot and D.Foo goes in the second slot.

So now what happens with your call?

The compiler reasons that you are calling Foo on something of compile time type A, so it finds the first (and only) Foo slot on A.

At runtime, the contents of that slot is B.Foo.

So that's what's called.

Make sense now?


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

...