程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> Emit學習-答疑篇-Call和Callvirt的區別

Emit學習-答疑篇-Call和Callvirt的區別

編輯:關於.NET

之前在Emit的學習過程中,多次碰到了方法的調用,發現有時候是使用Call而 有時候是使用Callvirt,一直對這兩者的區別不甚了解。然後就查閱了MSDN, MSDN中對這兩者的解釋為:

l  Call:調用由傳遞的方法說明符指示的方法;

l  Callvirt:對對象調用後期綁定方法,並且將返回值推送到計算堆棧上。

但是看了之後還是很不明白,我想可能是因為中文版的緣故吧。今天下午再次 看到了對Callvirt指令的解釋,“對對象調用後期綁定方法”,突然想到,這個 好像是指多態的意思吧?在一看virt,應該就是virtual的縮寫,於是就更加肯定 了自己的想法(外派在農行,不能上網,不然在園子隨便一找就有結果了,傷心 啊!),立馬動手開始實踐。

我們用最經典的Animal的例子來驗證這個想法,首先定義相關的類型,如下:

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方法,從而驗證之前的想法。由於方法的實現比較簡單,這裡就直接通過 代碼的注釋進行講解,代碼如下:

DynamicMethod

class Program

{

    private delegate void SpeakDelegate(Animal animal);


    static void Main(string[] args)

    {

        //定義動態方法,沒有返回值,傳入參數為Animal,所在的模塊

選擇為Program類所在的模塊

        DynamicMethod dynamicSpeakWithCall = new DynamicMethod

("DynamicSpeakWithCall", null, new 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", null, new 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

PS:由於學習Emit才只有幾天的時間,所以上面的分析都顯得有點膚淺,只是 簡單的記錄下自己的學習過程,如果各位看官能夠給我一點深層次的分析,我將 不甚感激。

本文配套源碼

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved