·您现在的位置: 云翼网络 >> 文章中心 >> 网站建设 >> 网站建设开发 >> ASP.NET网站开发 >> 结合IL和Windbg来看.Net调用继承虚方法的执行顺序

结合IL和Windbg来看.Net调用继承虚方法的执行顺序

作者:佚名      ASP.NET网站开发编辑:admin      更新时间:2022-07-23

先上测试代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestVirt
{
    class PRogram
    {
        static void Main(string[] args)
        {
            A c1 = new C();
            c1.Foo();

            C c2 = new C();
            c2.Foo();

            Console.ReadLine();
        }
    }

    class A
    {
        public virtual void Foo()
        {
            Console.WriteLine("Call on A.Foo()");
        }
    }

    class B : A
    {
        public override void Foo()
        {
            Console.WriteLine("Call on B.Foo() ");
        }
    }

    class C : B
    {
        public new void Foo()
        {
            Console.WriteLine("Call on C.Foo()");
        }
    }
}
View Code

可能你对C c2 = new C();这个的结果没有什么疑问,但是对A c1 = new C();的结果百思不解。呵呵,我们慢慢来看这个区别,先来看看最终的IL代码是什么样子的:

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // 代码大小       34 (0x22)
  .maxstack  1
  .locals init ([0] class TestVirt.A c1,
           [1] class TestVirt.C c2)
  IL_0000:  nop
  IL_0001:  newobj     instance void TestVirt.C::.ctor()
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  callvirt   instance void TestVirt.A::Foo()
  IL_000d:  nop
  IL_000e:  newobj     instance void TestVirt.C::.ctor()
  IL_0013:  stloc.1
  IL_0014:  ldloc.1
  IL_0015:  callvirt   instance void TestVirt.C::Foo()
  IL_001a:  nop
  IL_001b:  call       string [mscorlib]System.Console::ReadLine()
  IL_0020:  pop
  IL_0021:  ret
} // end of method Program::Main

  

根据IL的结果,我们明显可以看到,两次调用不同的地方就在于一个是Call的A的Foo,一个是C的Foo。

但是这里你注意了:我们new的是同样的一个对象,他们具有同样的内存布局。

用WinDbg来看看我们new出来对象的MethodTable是长什么样子的吧:

看到没有,这个C对象的方法表里面同时包括了C自己定义的Foo和上一层次父对象的Foo方法。

 

结合IL的结果和C对象的方法表的Dump结果,相信看官已经明白为啥两次调用为啥会用不同了吧。

 

算了,还是简单描述一下吧:首先根据il的结果明显两次调用请求的方法是不同的;其次,你可以看到我们的C对象引用的方法表里面确实有两个Foo方法。

呵呵,这样同样类型的对象对不同方法调用的请求是不是就可以分开了呢?当然是!

PS:可能会有人问:为啥我请求的A.Foo()你这个MethodTable里面没有呢?

脑补下吧哥:被B给override了。