在上一篇博文中,我們知道了委托就是一種用來聲明一個變量的數據類型,只不過委托聲明的變量可以接受一個方法,只要方法簽名保持一致就行了。
今天繼續介紹委托。
(一)委托的本質就是class:
為什麼說委托的本質就是class呢?我們知道當我們用C#編寫完源代碼後都要對項目進行編譯,我們運行的C#代碼實際上都是編譯後的代碼,編譯後的代碼我們成為:微軟中間代碼。
那我們就新建一個項目,在項目中只添加一個class,然後編寫我們的C#源代碼,然後接著就編譯項目。讓VS幫我們生成微軟中間代碼。
所以我們來看看編寫一個class編譯後的代碼是什麼樣子,那就新建一個項目,裡面添加一個Program.cs類文件,如下:
好了,接著在Program裡寫個Main方法,如下:
然後編譯這個項目,讓VS幫我們編譯C#源代碼,如下:
那我們編寫的代碼已經編譯成功了,我們去項目所在文件夾裡找到編譯後的文件:
然後定位到debug文件夾裡:
上圖中,第一個文件就是我們編譯後的文件:DemoForDelegate,編譯後的文件名和我們新建的項目名稱是一致的:DemoForDelegate。
那麼現在得到了編譯後的文件,這個就包含了我們編譯後的中間代碼了,所以我們現在需要查看這個文件裡代碼是什麼樣子,那就需要有一種相應的工具來查看。
這種工具就是:ILDasm,那我們去找我們電腦的系統盤裡找到這個工具,因為我系統裝在C盤,所以我去C盤把它找出來:
我找到了,它在這個目錄下:C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools
然後雙擊打開它,如下:
所以呢,再把我們剛才編譯後的項目托進去查看編譯後的中間代碼是什麼樣子:
之後:
我們看到編譯後的文件裡包含了項目:DemoForDelegate,這個項目唯一的Program類也包含進來了,所以和我們想象中差不多,該有的都有了。
同時,我們看在Program類下面還有.class private auto ansi beforefieldinit ,.ctor:void(),Main:void(string[])這3個成員,它們分別是:Program類,Program類的構造函數,Main方法。我們只要用鼠標雙擊這個3個成員就可以查看編譯後的代碼了,我們雙擊.ctor:void()看看:
那麼到現在,我們已經知道如何查看C#編譯後的代碼了,接著回到委托。那麼我們在Program類裡添加一個委托吧:
再編譯,然後再ILDasm裡查看發生了什麼:
從上圖中我們可以看到委托最終也被編譯成了一個同名的類,所以說委托的本質也是一個類。
(二)泛型委托:
一般在我們項目中會使用委托,所以我們來定義幾個委托:
1 namespace DemoForDelegate 2 { 3 public delegate void delegateInt(int m); 4 public delegate void delegatedouble(double d); 5 public delegate void delegatestring(string str); 6 public delegate void delegatefloat(float f); 7 public delegate void delegatedecimal(decimal d); 8 }
我們定義了5個委托,這5個委托用於接受不同的方法。
但是,我們仔細找下規律就會發現其實這5個委托很相似:返回類型都是void,方法輸入參數為1個。不同的是參數的數據類型。那麼我想簡化一下代碼,想寫一個通用的委托來取代上面那5個委托,既然它們的差異是參數的數據類型,那麼很容易想到用泛型來讓代碼變得通用,如下:
1 namespace DemoForDelegate 2 { 3 //public delegate void delegateInt(int m); 4 //public delegate void delegatedouble(double d); 5 //public delegate void delegatestring(string str); 6 //public delegate void delegatefloat(float f); 7 //public delegate void delegatedecimal(decimal d); 8 9 public delegate void MyAction<T>(T arg); 10 }
這樣用一個委托就搞定了,所以在我們項目可以這樣多定義一些這樣的泛型委托:
1 namespace DemoForDelegate 2 { 3 public delegate void MyAction(); 4 public delegate void MyAction<T>(T arg); 5 public delegate void MyAction<T1, T2>(T1 arg1, T2 arg2); 6 public delegate void MyAction<T1, T2, T3>(T1 arg1, T2 arg2,T3 arg3); 7 public delegate void MyAction<T1, T2, T3, T4>(T1 arg1, T2 arg2,T3 arg3,T4 arg4); 8 //more... 9 }
上面的委托都沒有返回值,那我們再定義一些帶返回值的委托吧:
1 namespace DemoForDelegate 2 { 3 public delegate void MyAction(); 4 public delegate void MyAction<T>(T arg); 5 public delegate void MyAction<T1, T2>(T1 arg1, T2 arg2); 6 public delegate void MyAction<T1, T2, T3>(T1 arg1, T2 arg2,T3 arg3); 7 public delegate void MyAction<T1, T2, T3, T4>(T1 arg1, T2 arg2,T3 arg3,T4 arg4); 8 //more... 9 10 //帶返回值的委托 11 public delegate TResult MyFunc<out TResult>(); 12 public delegate TResult MyFunc<out TResult,in T1>(T1 arg1); 13 public delegate TResult MyFunc<out TResult,in T1,in T2>(T1 arg1,T2 arg2); 14 public delegate TResult MyFunc<out TResult,in T1,in T2,in T3>(T1 arg1, T2 arg2,T3 arg3); 15 //more... 16 17 }
至於上面的委托名稱取:MyAction,MyFunc,哈哈,不解釋了,就一個名稱而已,你懂。
如果大家有關C#技術方面更多的討論可以加我的一個技術QQ群:240749438。