.Net——IL之方法调度

简述

在CLR中,以static修饰符来定义静态方法,而以instance修饰符来定义实例方法,二者的区别是静态方法只与类型相关,在编译期即可确定执行的操作,因此是静态的;而实例方法只与实例相关,在运行期才能决定执行的操作,因此是动态的。

  1. 方法定义及IL
    在这里插入图片描述
    在这里插入图片描述

  2. 方法调用及IL
    在这里插入图片描述
    在这里插入图片描述

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

直接调度

直接调度包括:call指令的静态调度和callvirt指令的虚拟调度。
用CIL写程序:从“call vs callvirt”看方法调用

call在某种情况下可以调用虚方法,而callvirt也可以调用非虚方法。具体的情况包括:
(1)call调用虚方法的情况
●密封类型的引用调用虚方法时,采用call调用可以减少callvirt进行类型检查的时间,提高调用性能。
●值类型调用虚方法时,因为值类型首先是密封的,其次call调用可以阻止值类型被执行装箱。
●基类调用虚方法时,采用call可以避免callvirt递归调用本身引起的堆栈溢出。常见的覆写例如,实现System.Object的虚方法Equals()、ToString()时,就采用call调用方式。

(2)callvirt调用非虚方法的情况
●常见于在引用类型中调用非虚方法的情况,其原因是callvirt调用时,如果引用变量为null则会抛出NullReferenceException,而call调用则不会抛出任何异常。为类型安全起见,在C#中会调用callvirt来完成引用类型的非虚方法调用。

call和callvirt指令似乎并无明确的规律,对虚方法与非虚方法的调用没有找到严格的界定,其实这就对了。例如,基于执行性能的考虑,在密封类中以call指令来调用虚方法会更好;而基于安全机制的考虑,则在引用类型中以callvirt指令来调用非虚方法会更安全。
当然,我们对这两个指令的把握,还是有一定的原则可循,这就是:call指令调用静态类型、声明类型的方法,而callvirt调用动态类型、实际类型的方法。万变不离其宗,这条规则就是call指令与callvirt指令骨子里的区别。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值