Emit学习-答疑篇-Call和Callvirt的区别

之前在Emit的学习过程中,多次碰到了方法的调用,发现有时候是使用Call而有时候是使用Callvirt,一直对这两者的区别不甚了解。然后就查阅了MSDNMSDN中对这两者的解释为:

l  Call:调用由传递的方法说明符指示的方法;

l  Callvirt:对对象调用后期绑定方法,并且将返回值推送到计算堆栈上。

但是看了之后还是很不明白,我想可能是因为中文版的缘故吧。今天下午再次看到了对Callvirt指令的解释,“对对象调用后期绑定方法”,突然想到,这个好像是指多态的意思吧?在一看virt,应该就是virtual的缩写,于是就更加肯定了自己的想法(外派在农行,不能上网,不然在园子随便一找就有结果了,伤心啊!),立马动手开始实践。

我们用最经典的Animal的例子来验证这个想法,首先定义相关的类型,如下:

ContractedBlock.gif ExpandedBlockStart.gif Animal
class Animal
{
    
public virtual void Speak()
    {
        Console.WriteLine(
"Animal.Speak");
    }
}

class Cat : Animal
{
    
public override void Speak()
    {
        Console.WriteLine(
"Cat.Speak");
    }
}

class Dog : Animal
{
    
public override void Speak()
    {
        Console.WriteLine(
"Dog.Speak");
    }
}

由于只是实现简单的方法调用,所以我们在这里选择使用DynamicMethod而不再创建动态程序集,顺便也可以演练下DynamicMethod的使用。要使用DynamicMethod我们首先要定义一个委托,用来执行方法的调用,定义如下:

private delegate void SpeakDelegate(Animal animal);

到时候我们通过此委托,传入一个Animal类或者其派生类的实例,并调用里面的Speak方法,从而验证之前的想法。由于方法的实现比较简单,这里就直接通过代码的注释进行讲解,代码如下:

ContractedBlock.gif ExpandedBlockStart.gif DynamicMethod 
class Program
{
    
private delegate void SpeakDelegate(Animal animal);

    
static void Main(string[] args)
    {
        
//定义动态方法,没有返回值,传入参数为Animal,所在的模块选择为Program类所在的模块
        DynamicMethod dynamicSpeakWithCall = new DynamicMethod("DynamicSpeakWithCall"nullnew Type[] { typeof(Animal) }, typeof(Program).Module);

        ILGenerator callIL 
= dynamicSpeakWithCall.GetILGenerator();

        
//加载参数0 即 Animal类或其派生类的对象
        callIL.Emit(OpCodes.Ldarg_0);
        
//通过Call指令调用Speak方法
        callIL.Emit(OpCodes.Call, typeof(Animal).GetMethod("Speak"));
        callIL.Emit(OpCodes.Ret);

        Console.WriteLine(
"SpeakWithCall:");
        SpeakDelegate SpeakWithCall 
= (SpeakDelegate)dynamicSpeakWithCall.CreateDelegate(typeof(SpeakDelegate));
        SpeakWithCall(
new Animal());
        SpeakWithCall(
new Cat());
        SpeakWithCall(
new Dog());

        
//定义动态方法,没有返回值,传入参数为Animal,所在的模块选择为Program类所在的模块
        DynamicMethod dynamicSpeakWithCallvirt = new DynamicMethod("DynamicSpeakWithCallvirt"nullnew Type[] { typeof(Animal) }, typeof(Program).Module);

        ILGenerator callvirtIL 
= dynamicSpeakWithCallvirt.GetILGenerator();

        
//加载参数0 即 Animal类或其派生类的对象
        callvirtIL.Emit(OpCodes.Ldarg_0);
        
//通过Callvirt指令调用Speak方法
        callvirtIL.Emit(OpCodes.Callvirt, typeof(Animal).GetMethod("Speak"));
        callvirtIL.Emit(OpCodes.Ret);

        Console.WriteLine(
"SpeakWithCallvirt:");
        SpeakDelegate SpeakWithCallvirt 
= (SpeakDelegate)dynamicSpeakWithCallvirt.CreateDelegate(typeof(SpeakDelegate));
        SpeakWithCallvirt(
new Animal());
        SpeakWithCallvirt(
new Cat());
        SpeakWithCallvirt(
new Dog());
    }
}

最后给出相应的输出结果:

SpeakWithCall:

Animal.Speak

Animal.Speak

Animal.Speak

SpeakWithCallvirt:

Animal.Speak

Cat.Speak

Dog.Speak

很明显,之前的推论是正确的,源码下载 CallCallvirt的区别

PS:由于学习Emit才只有几天的时间,所以上面的分析都显得有点肤浅,只是简单的记录下自己的学习过程,如果各位看官能够给我一点深层次的分析,我将不甚感激。

转载于:https://www.cnblogs.com/yingql/archive/2009/03/23/1420000.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值