call、callvirt和calli指令用于完成方法调用,有何区别呢?

1)call使用静态调度,也就是根据引用类型的静态类型来调度方法。call指令根据引用变量的类型来调用方法,因此通常用于调用非虚方法。

2)callvirt使用虚拟调度,也就是根据引用类型的动态类型来调度方法;callvirt指令根据引用变量指向的对象类型来调用方法,执行时会递归的调用给自己知道堆栈溢出,从而实现了在运行时的动态绑定,因此通常用于调用虚方法。

3)calli又称间接调用,是通过函数指针来执行方法调用的。与call和callvirt相对应的(直接调用)

Father类

public class Father
    {
        public void DoWork()
        {
            Console.WriteLine("Father.DoWork()");
        }

        public virtual void DoVirtualWork()
        {
            Console.WriteLine("Father.DoVirtualWork()");
        }

        public virtual void DoVirtualAll()
        {
            Console.WriteLine("Father.DoVirtualAll()");
        }
    }

Son类

public class Son:Father
    {
        public static void DoStaticWork()
        {
            Console.WriteLine("Son.DoStaticWork()");
        }

        public new void DoWork()//new表示对父类的阻断
        {
            Console.WriteLine("Son.DoWork()");
        }

        public new virtual void DoVirtualWork()
        {
            Console.WriteLine("Son.DoVirtualWork()");
        }

        public override void DoVirtualAll()
        {
            base.DoVirtualAll();
            Console.WriteLine("Son.DoVirtualAll()");
        }
    }

GrandSon类

public class GrandSon:Son
    {
        public override void DoVirtualWork()
        {
            base.DoVirtualWork();
            Console.WriteLine("GrnadSon.DoVirtualWork()");
        }

        public override void DoVirtualAll()
        {
            base.DoVirtualAll();
            Console.WriteLine("GrandSon.DoVirtualAll()");
        }
    }

Prgram.cs

class Program
    {
        static void Main(string[] args)
        {
            Father son = new Son();
            son.DoWork();
            son.DoVirtualWork();

            Son.DoStaticWork();

            Father aGrandSon = new GrandSon();
            aGrandSon.DoWork();
            aGrandSon.DoVirtualWork();
            aGrandSon.DoVirtualAll();

            Console.ReadLine();
        }
    }

输出结果  

  

IL代码

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // 代码大小       61 (0x3d)
  .maxstack  1
  .locals init ([0] class ConsoleApplication1.Father son,
           [1] class ConsoleApplication1.Father aGrandSon)
  IL_0000:  nop
  IL_0001:  newobj     instance void ConsoleApplication1.Son::.ctor()
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  callvirt   instance void ConsoleApplication1.Father::DoWork()
  IL_000d:  nop
  IL_000e:  ldloc.0
  IL_000f:  callvirt   instance void ConsoleApplication1.Father::DoVirtualWork()
  IL_0014:  nop
  IL_0015:  call       void ConsoleApplication1.Son::DoStaticWork()
  IL_001a:  nop
  IL_001b:  newobj     instance void ConsoleApplication1.GrandSon::.ctor()
  IL_0020:  stloc.1
  IL_0021:  ldloc.1
  IL_0022:  callvirt   instance void ConsoleApplication1.Father::DoWork()
  IL_0027:  nop
  IL_0028:  ldloc.1
  IL_0029:  callvirt   instance void ConsoleApplication1.Father::DoVirtualWork()
  IL_002e:  nop
  IL_002f:  ldloc.1
  IL_0030:  callvirt   instance void ConsoleApplication1.Father::DoVirtualAll()
  IL_0035:  nop
  IL_0036:  call       string [mscorlib]System.Console::ReadLine()
  IL_003b:  pop
  IL_003c:  ret
} // end of method Program::Main

  

[札记]IL经典指令解析之方法调度的更多相关文章

  1. .NET中常用的几种解析JSON方法

    一.基本概念 json是什么? JSON:JavaScript 对象表示法(JavaScript Object Notation). JSON 是一种轻量级的数据交换格式,是存储和交换文本信息的语法. ...

  2. Java学习笔记之方法重载,动态方法调度和抽象类

    一.方法重载 如果子类中的方法与它的超类中的方法有相同的方法名,则称子类中的方法重载超类中的方法,特别是当超类和子类中的方法名和参数类型都相同时,在子类中调用该方法时,超类中的方法会被隐藏.考虑下面程 ...

  3. C# 解析js方法,并调用js方法

    本文转载:http://www.cnblogs.com/StudyLife/archive/2013/03/11/2953516.html 本文不是基于B/S的 后台调用前台js方法,而是给你一段js ...

  4. angularjs(二)模板终常用的指令的使用方法

    通过使用模板,我们可以把model和controller中的数据组装起来呈现给浏览器,还可以通过数据绑定,实时更新视图,让我们的页面变成动态的.ng的模板真是让我爱不释手.学习ng道路还很漫长,从模板 ...

  5. Emit学习(2) - IL - 常用指令介绍

    学习Emit必不可少的, 会使用到IL中间代码. 初见IL代码, 让我有一种汇编的感觉, 让我想起了, 大学时, 学习8051的汇编语言. 多的就不扯了, 直接进入正题, OpCodes指令集是不是有 ...

  6. U-BLOX GPS 模块及GPRMC指令解析

    受朋友所托,调试一款GPS模块,该模块是UBLOX的NEO-6M GPS模组.想到用这款GPS的人较多,自己日后也有可能在用到这个模块,就写下这份笔记. 1. 介绍 基本信息如下: 1, 模块采用U- ...

  7. SpringJDBC解析4-query方法

    重要步骤说明: 首先是从PersonServiceImpl方法进去,调用JdbcTemplate的query方法,然后执行一连串错中复杂的调用,而且里面有很多函数都是以回调形式处理, 1)JdbcTe ...

  8. Dapper使用方法:dapper-dot-net/Tests/Tests.cs解析(1)方法:TestMultiMapWithConstructor

    sql: SELECT * FROM users; SELECT * FROM posts; SELECT * FROM Posts p LEFT JOIN Users u ON u.Id= p.Ow ...

  9. PHP获取解析URL方法

    们要经常对url里面所带的参数进行解析,如果我们知道了url传递参数名称,例如: /index.php?name=tank&sex=1#top 我们就可以通过$_GET['name'],$_G ...

随机推荐

  1. HTML5的新语义化的标签

    在HTML5之前采用HTML+CSS文档结构写法 [ID选择器说明 id选择器——用于标识页面上特定元素(比如站点导航.页眉.页脚)而且必须唯一; 也可以用来标识持久结构性元素(如主导航.内容区域)] ...

  2. 解决:PADS导入.DXF结构图出现坐标超出范围问题

    现象: 原因: PCB尺寸是有限的,PADS中对于坐标大小有所限制,但AUTO CAD中的坐标却是无限制的. 解决方法: 1.在AUTO中使用M命令,将绘制的结构图移动至原点: 2.在AUTO中使用W ...

  3. ListView遍历每个Item出现NullPointerException的异常

    在使用ListView过程中我们有时候需要遍历取得每个Item项中的一些数据(比如每个Item里面有TextView,需要获取它的文本等等),但是我们在遍历过程中经常会遇到NullPointerExc ...

  4. easyui1.3.2中使用1.3.6或1.4.x的calendar

    首先在1.3.2中calendar控件不支持日历某天的颜色进行改变,和自定义回调函数 Name Type Description Default width number The width of c ...

  5. ArrayList如何保证线程安全

    ArrayList是线程不安全的,轻量级的.如何使ArrayList线程安全? 1.继承Arraylist,然后重写或按需求编写自己的方法,这些方法要写成synchronized,在这些synchro ...

  6. Java利用Preferences设置个人偏好

    Java利用Preferences设置个人偏好 Preferences的中文意思即偏好或喜好的意思,也就是说同一个程序在每次运行完后,可以通过Preferences来记录用户的偏好,下次启动时,程序会 ...

  7. 【原】iOS学习之XMPP环境搭建

    XMPP环境搭建 1> 搭建XMPP环境需要几个辅助工具: Java Openfire 采用Java开发,因此我们需要先安装Java环境 XAMPP XAMPP(Apache+MySQL+PHP ...

  8. Q114第一颗二叉查找树(链式)

    输入n,然后n个树,建立二叉查找树.从小到大输出每个节点的左右子树,空输出# #include<cstdio> #include<iostream> using namespa ...

  9. hdu Super Jumping

    简单的dp,最优子结构是dp[i],即从0~i来看,是的dp[i]最大,然后找到最大中的最大就可以了, 转移方程是:dp[i]=max{dp[i],dp[j]+value[i]},注意这里有两个判断条 ...

  10. 同步灵无线锂电鼠G11-580HX独特“五灵键”

    http://tieba.baidu.com/p/2130455709 现在鼠标功能越来越强大,游戏鼠标的宏设置,办公鼠标的复制粘贴等.各位有没有给鼠标设置一些好玩.方便.搞怪.有意思的的功能的呢?笔 ...