C#中委托是一種類型。可以這么籠統的理解:int型變量代表一個整型,而委托類型的變量代表一個方法的地址(將方法名稱傳入constructor並實例化該委托變量)。
--By Brisk Yu
1 為何要使用委托
我覺得網上關於什么現實生活的舉例並不好,還是要從程序的本質去理解:
1)程序是由事件驅動的。
2)事件發生時,操作系統需要知道事件對應的處理函數。例如,用戶按下鼠標時操作系統需要知道此時該做什么,是關閉窗口呢,還是打開某個文件呢?當網卡接收到數據包時操作系統也需要知道此時該做什么,是往上層傳輸呢,還是丟棄呢?
3)因此,我們需要將事件對應的處理函數提前告知操作系統(向操作系統注冊),操作系統在發生該事件時,調用對應的處理函數,這便是回調,對應的處理函數也被稱為回調函數。
4)那么我們如何向操作系統注冊回調函數呢(如何讓操作系統知道發生對於事件它該干嘛呢)?對於C++,我們使用pointer,而對於C#,我們使用delegate。
2 如何使用委托
先從最基本的創建委托的方法開始,逐步變換為使用匿名方法和lambda expression。
1)最原始用法,用方法名初始化一個委托類型變量,調用該委托類型變量,執行承載的方法:
public delegate int SomeDelegate(int i); int SomeFunction1(int i) { Console.WriteLine("func1"+i); return 3; } 。。。Main Function { SomeDelegate sd = new SomeDelegate(SomeFunction1); sd(2); }
2)如1)中,如果我們使用委托都需要定義一個委托類型比較麻煩,因此我們使用匿名委托:
刪去1)中的
public delegate int SomeDelegate(int i);
並將main function中的代碼改為:
Func<int, int> sd= new Func<int, int>(SomeFunction1); sd(2);
Func和Action是C#為我們定義好了委托類型。Func指有返回參數的委托類型,其<>中最后一個參數既是返回參數的類型;Action指無返回參數的委托類型。
3)既然定義委托類型的代碼可以拿掉,那么相應的方法聲明與定義的語句也可以拿掉:
刪去1)中的方法聲明與定義的語句:
int SomeFunction1(int i) {
Console.WriteLine("func1"+i);
return 3;
}
將main function 中的代碼改為:
Func<int, int> sd = new Func<int, int>(delegate (int s) { Console.WriteLine("匿名方法" + s); return 88; }); int i = sd(2);
此時,Func()中的代碼稱為匿名方法,即沒有方法名。
4)我們對3)中的代碼進一步修改,將匿名方法改為lambda表達式。(lambda表達式是匿名方法的一種表示方法)
將mian function中的代碼改為:
Func<int, int> sd = new Func<int, int>(s=> { Console.WriteLine("匿名方法"+s); return 88; }); int i = sd(2);
此時,對於lambda表達式,編譯器會自動判斷其類型,因此無需特指其類型。
3 實際應用
我們參考一下winform中鼠標點擊事件響應是如何實現的
1)在System命名空間中定義一個委托類型
namespace System { // // 摘要: // 表示將用於處理不具有事件數據的事件的方法。 // // 參數: // sender: // 事件源。 // // e: // 不包含事件數據的對象。 [ComVisible(true)] public delegate void EventHandler(object sender, EventArgs e); }
2)在Control.cs(所有控件的父類)中定義一個EventHandler型的委托Click
public event EventHandler Click;
注:這里用到了event關鍵字,表明這個委托是一個事件。其實是指一簇委托。如果理解不了姑且將event拿掉來看。
3)編寫鼠標點擊事件響應代碼
private void buttonStart_Click(object sender, EventArgs e) { //TODO }
4)用3)中方法實例化一個委托賦給Click
this.buttonStart.Click += new System.EventHandler(this.buttonStart_Click);
至此,程序便可以響應buttonStart這個按鈕的響應事件了。更加具體的操作會深入到操作系統中,這里不再敘述。
--By Brisk Yu