结合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()");
}
}
}
可能你对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了。
结合IL和Windbg来看.Net调用继承虚方法的执行顺序的更多相关文章
- Odoo(OpenERP) 多个子类重载同一个父类方法的执行顺序及如何调用父类的父类方法
首先说下起因,在修改英国会计模块(没错,就是那个安格鲁撒克逊记账模式!)中不符合中国国情的部分供能时,碰到了一个棘手的问题,简单的说就是B类继承它的父类A并重载了A的方法M,同时C类也继承了A类也重载 ...
- 实现继承+接口继承+虚方法+隐藏方法+this/base+抽象类+密封类/方法+修饰符
概念: 在上一节课中学习了如何定义类,用类当做模板来声明我们的数据. 很多类中有相似的数据,比如在一个游戏中,有Boss类,小怪类Enemy,这些类他们有很多相同的属性,也有不同的,这个时候我们可以使 ...
- odoo开发笔记 -- 多个子类继承同一个父类方法的执行顺序
场景描述: odoo模块化开发的架构理念,科学&高效, 可以让很多业务场景,尽可能松耦合:让开发人员的主要精力,关注在当前的业务逻辑: 所谓「前人栽树,后人乘凉」,模块整体好比一棵大树, 开发 ...
- Java基础-继承-子类与父类执行顺序
代码 public class Test { public static void main(String[] args) { new Circle(); } } class Draw { publi ...
- Java 继承中构造方法的执行顺序问题
在Java中,如果一个类没有任何显式创建的构造器则该类默认会有一个无参构造器:如果显式创建了有参构造器则该类就不再有默认无参构造器. 在Java继承中,构造器并不能被继承,而是被显示或隐式调用. 1. ...
- java中子类继承父类程序执行顺序问题
Java中,new一个类的对象,类里面的静态代码块.非静态代码.无参构造方法.有参构造方法.类的一般方法等部分,它们的执行顺序相对来说比较简单,用程序也很容易验证.比如新建一个测试父类. public ...
- super方法 调用父类的方法
描述 super() 函数是用于调用父类(超类)的一个方法. super 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO).重复 ...
- Java 基础:继承中的执行顺序
1.单独的父类测试 Java中,new一个类的对象,类里面的静态代码块.非静态代码.无参构造方法.有参构造方法.类的一般方法等部分, 它们的执行顺序相对来说比较简单,用程序也很容易验证. 比如新建一个 ...
- java中子类继承父类程序执行顺序
java中子类继承父类程序执行顺序 FatherTest.java public class FatherTest { private String name; public FatherTest() ...
随机推荐
- 「BZOJ 1791」「IOI 2008」Island「基环树」
题意 求基环树森林所有基环树的直径之和 题解 考虑的一个基环树的直径,只会有两种情况,第一种是某个环上结点子树的直径,第二种是从两个环上结点子树内的最深路径,加上环上这两个结点之间的较长路径. 那就找 ...
- C++期中考试
第一题1. 补足日期类实现,使得能够根据日期获取这是一年中第多少天.(12分) date.h #ifndef DATE_H #define DATE_H class Date { public: Da ...
- jQuery回车触发事件
举例: 需求:要求回车触发下一步 Html部分 <div style="margin-top: 25px;"> <a href="#" cla ...
- 【bzoj2190】: [SDOI2008]仪仗队 数论-欧拉函数
[bzoj2190]: [SDOI2008]仪仗队 在第i行当且仅当gcd(i,j)=1 可以被看到 欧拉函数求和 没了 /* http://www.cnblogs.com/karl07/ */ #i ...
- Python列表知识补充
1.import this Python之禅,圣经. >>> import this The Zen of Python, by Tim Peters Beautiful is b ...
- js中 关于DOM的事件操作
一.JavaScript的组成 JavaScript基础分为三个部分: ECMAScript:JavaScript的语法标准.包括变量.表达式.运算符.函数.if语句.for语句等. DOM:文档对象 ...
- git配置项目
1.下载安装完git 2.在git oschina上发布项目 3.管理-公匙管理 4.git上面生成公匙 $ cat ~/.ssh/id_rsa.pub 5.将公匙复制进 git oschina 管理 ...
- ORACLE 中dbms_stats的使用
dbms_stats能良好地估计统计数据(尤其是针对较大的分区表),并能获得更好的统计结果,最终制定出速度更快的SQL执行计划. exec dbms_stats.gather_schema_stats ...
- C语言数据结构-顺序线性表的实现-初始化、销毁、长度、查找、前驱、后继、插入、删除、显示操作
1.数据结构-顺序线性表的实现-C语言 #define MAXSIZE 100 //结构体定义 typedef struct { int *elem; //基地址 int length; //结构体当 ...
- asp.net core 简化模型验证 modelState.IsValid不用每一个写
第一种:直接在执行action之前验证模型 实现 IActionFilter public class ModelStateFilter : IActionFilter { public void O ...