zoukankan      html  css  js  c++  java
  • 结合IL和Windbg来看.Net调用继承虚方法的执行顺序

    先上测试代码:

    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了。

  • 相关阅读:
    vue.js中英文api
    easyui combobox重复渲染问题
    大数据新兴思维
    机器学习技法 之 矩阵分解(Matrix Factorization)
    机器学习技法 之 终章(Final)
    CMake 中文简易手册
    线性判别分析(Linear Discriminat Analysis)
    梯度提升机(Gradient Boosting Machine)之 XGBoost
    机器学习技法 之 梯度提升决策树(Gradient Boosted Decision Tree)
    Host是什么?如何设置host文件?
  • 原文地址:https://www.cnblogs.com/12taotie21/p/4295382.html
Copyright © 2011-2022 走看看