结合IL和Windbg来看.Net调用继承虚方法的执行顺序
2015-02-17 18:35
288 查看
先上测试代码:
View Code
可能你对C c2 = new C();这个的结果没有什么疑问,但是对A c1 = new C();的结果百思不解。呵呵,我们慢慢来看这个区别,先来看看最终的IL代码是什么样子的:
根据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了。
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了。
相关文章推荐
- 关于JAVA继承类的静态变量、成员变量、父子类构造方法调用顺序的研究
- java中结合单例模式,控制单例类的某方法在被多线程调用时,只被1个线程调用执行,执行完毕后才被另一线程调用
- LayoutInflater.inflate()调用后View的构造方法和onFinishInflate()方法执行的顺序
- java继承中父类和子类静态、非静态代码块,构造函数,静态方法的执行顺序
- java中继承期间父子类型的初始化顺序以及重写方法的调用规则
- 所有的页面都继承自定义的BasePage,而有一个特殊页面要继承BasePage,但不想执行父类构造函数调用的某些方法,怎么办?
- 类继承中构造方法与static块调用顺序浅析
- 继承关系中,代码执行的顺序。静态代码块、静态方法、构造方法
- view的执行过程,各种方法的调用先后顺序
- 当子类继承父类时,构造块,静态块,静态方法的执行顺序
- 关于JAVA继承类的静态变量、成员变量、父子类构造方法调用顺序的探讨 .
- 继承--抽象类--接口--子类构造方法代码执行顺序
- 当应用程序开始执行时,系统方法调用的先后顺序
- 继承中的代码块和构造方法的执行顺序探索
- 类继承中子类static成员方法与父类static成员方法调用顺序浅析
- java中结合单例模式,控制单例类的某方法在被多线程调用时,只被1个线程调用执行,执行完毕后才被另一线程调用
- 子类继承父类(父类和子类里:块、静态块、构造和方法覆写)之间调用顺序
- Odoo(OpenERP) 多个子类重载同一个父类方法的执行顺序及如何调用父类的父类方法
- Java子类继承父类,构造方法的执行顺序问题
- 子类继承父类(父类和子类里:块、静态块、构造和方法覆写)之间调用顺序