结合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() ...
随机推荐
- 一看你就懂,超详细java中的ClassLoader详解(转)
转载地址 http://blog.csdn.net/briblue/article/details/54973413 目录(?)[-] Class文件的认识 你还记得java环境变量吗 J ...
- 2019.2.14 考试T1 FFT
\(\color{#0066ff}{ 题目描述 }\) 衡水二中的机房里经常有人莫名其妙地犇雷,leizi很生气,决定要找出那个犇雷的人 机房有n个人,每个人都认为机房里有两个人可能会犇雷,其中第i个 ...
- 10.8 wtx模拟题题解
填坑 orz w_x_c_q w_x_c_q的模拟赛(150pts,炸了) money 题目背景: 王小呆又陷入自己的梦里.(活在梦里...) 题目描述: 王小呆是一个有梦想的小菜鸡,那就是赚好多好多 ...
- CF709B Checkpoints 模拟
Vasya takes part in the orienteering competition. There are n checkpoints located along the line at ...
- [CEOI2008]order BZOJ1391 网络流
题目描述 有N个工作,M种机器,每种机器你可以租或者买过来. 每个工作包括若干道工序,每道工序需要某种机器来完成,你可以通过购买或租用机器来完成. 现在给出这些参数,求最大利润 输入输出格式 输入格式 ...
- CoreAnimation 核心动画 / CABasicAnimation/ CAKeyframeAnimation
- (void)createBaseAnimation{ //基础动画 CABasicAnimation *animation = [CABasicAnimation animation]; anim ...
- django内置服务器
单进程多线程的 多线程用来并发,各个线程之间不会阻塞,每个线程对应一个连接
- Jira的安装使用
1.什么是JIRA JIRA是目前比较流行的基于Java架构的管理系统,由于Atlassian公司对很多开源项目实行免费提供缺陷跟踪服务,因此在开源领域,其认知度比其他的产品要高得多,而且易用性也好一 ...
- sql 日期对比
来自这里
- MYSQL生成两个日期之间的所有日期数据
set @i = -1; set @sql = repeat(" select 1 union all",-datediff('2021-01-01','2030-12-31')+ ...