最經在學習LinqtoSql,然后扯到Lambda表達式,然后扯到匿名方法,然后扯到委托,最后扯到事件處理。。。后來發現對委托這個概念和事件處理這個過程理解得不是很清晰,遂得一下學習筆記。那里說得不對,請大家多多指教!
第一部分:理解委托
委托委托,顧名思義,就是類似於中間人的意思,有些事情你不做,委托別人去做,比如你想相親,但你不想去主動約女孩子,那你可以交給媒婆去幫你約。
如果你學過C++,請把委托理解成函數指針,都是為了調用函數。函數指針可以調用符合該函數指針要求的函數。什么叫符合該函數指針要求?就是被調用的函數擁有和該函數指針一樣的返回類型、參數的個數相同、對應參數的類型一致。
函數指針舉例說明。int (*p)(int,int);定義了一個函數指針p,p只能調用 函數原型(或者說函數簽名)是 返回類型為int、只有兩個參數並且參數類型都是int的函數。
委托舉例說明:delegate void MyDelegate(int a,int b);聲明了一種委托類型 MyDelegate(委托有不同類型,就好像中間人有不同類型,你想相親就找媒婆這種中間人,你想看風水,就找風水大師這種中間人),這種委托類型只能調用 返回類型是void、只有兩個參數並且參數類型都是int的函數。跟函數指針是不是很像?
委托其實就是一個類,委托的基類是Delegate 類,只不過我們不能顯示地從 Delegate 類派生出委托類(Delegate 類不是委托類型,它的派生類才是),這是給系統和編譯器用的。只不過類實例化之后就叫對象,而委托實例化之后還是叫委托而已,另外實例化委托必須提供一個相對應的函數作為參數。
舉例說明定義委托:(參考自:http://www.cnblogs.com/warensoft/archive/2010/03/19/1689806.html)
1、定義一個函數Max,函數簽名位:返回類型為int,兩個參數,參數類型都是int
int Max(int x,int y) {return x>y?x:y;}
2、創建一個委托類型(名字是MyDelegate),並聲明該委托類型可以調用的函數的函數原型(函數簽名)為:返回類型為int,兩個參數,參數類型都是int。注意,委托是一個類,創建委托類型要放在函數外面
delegate int MyDelegate(int a,int b);
3.建立一個委托類的實例(或者說MyDelegate的實例),並指向要調用的方法,有兩種方式:
//利用委托類的構造方法指定,這是最為常見的一種方式
MyDelegate md = new MyDelegate(Max);
//利用自動推斷方式來指明要調用的方法,該形式更類型於函數指針
MyDelegate md = Max;
用第一種方式創建委托實例時必須提供一個函數簽名符合該委托類型的函數作為參數。
4、利用委托類實例調用所指向的方法
int c = md(4,5);
總結:可以把委托理解成函數指針,可以調用函數簽名和委托類型一致的函數
第二部分:事件處理(本文主要想表達對委托的理解,所以這部分以后再詳說)
事件處理涉及到兩個對象:一個是事件源(就是觸發該事件的對象),另一個是事件接收者(提供了處理方法的類)。兩者本無聯系。
事件處理的過程:首先事件源觸發了某事件,委托捕獲到這件事(委托通過訂閱該事件實現),委托調用事件接收類中的相應函數進行處理。
舉例說明:this.button1.Click += new System.EventHandler(this.button1_Click);
事件源是button1,觸發的事件是 按鈕單擊事件 Click,委托是 System.EventHandler ,事件處理函數是 button1_Click 。上面代碼的意思是,System.EventHandler (委托)對 this.button1(事件源)的 Click (事件) 進行訂閱,當this.button1 的Click事件發生時,委托接收事件源傳過來的一些參數,接着調用 this.button1_Click (事件處理函數) 並把從事件源那里接收的參數傳給該函數作為參數。
第三部分:匿名方法
匿名方法就是沒有名字的方法(函數),既然沒有名字,就是說只有在定義的時候能調用,在其他地方就不能調用了(沒有名字啊,那就找不到嘛)。為什么要用到匿名方法呢?調用函數是需要花銷的,但有時候調用的一些方法很短小(例如一句話方法)、只完成很少的功能,這個時候就有點得不償失了,此時就可以定義一個匿名方法來完成這個功能了,而匿名方法作為內聯代碼,花銷相對小很多。匿名方法都是和委托連在一起用的(以后還有lambda表達式),以前創建委托實例時需要傳遞一個函數名給它作為參數,現在可以通過匿名方法直接把一段代碼傳進去了
定義匿名方法:用到delegate關鍵字,如:delegate(int a, int b){return a > b ? a : b ;} 代碼定義了一個匿名方法,該方法的參數是 int a 和 int b ,方法體是 {return a > b ? a : b}。如果只是定義一個匿名方法沒有意義,因為定義完過后你就再也不能用這個匿名方法,所以匿名方法要在定義的時候就馬上使用。一般來說就是初始化委托了。
使用匿名方法:

1 namespace DelegateTest
2 {
3 class Program
4 {
5 //創建委托類型
6 delegate int Mydelegate(int x, int y);
7 static void Main(string[] args)
8 {
9 //創建委托實例,指向匿名函數
10 Mydelegate mydelegate = delegate(int x,int y) { return x + y; };
11
12 //通過委托調用匿名方法
13 Console.WriteLine(mydelegate(3,2));
14
15 Console.ReadKey();
16 }
17 }
18 }
總結:匿名方法就是沒有名字的方法,只能通過委托來被調用(這句話可能有誤,匿名方法也可以直接訂閱事件作為事件處理函數,當事件發生時就接收相應參數並執行函數體)。
第四部分:Lambda
上面說到可以通過匿名方法以內聯代碼的方式來簡介地實現委托,但還有更簡潔的方法,那就是用lambda表達式來代替匿名方法,在這里,lambda表達式就是匿名方法的簡潔版。
Lambda表達式的語法如下:
(param1, param2 ...,paramN) =>
{
表達式1;
表達式2;
return 返回值;
}
param1, param2 ...,paramN 就是參數,不用確定類型,編譯器會做這個工作,花括號了就是lambda表達式要執行的語句,如果對應的委托類型有返回值,那么就要有return 語句。
把第三部分那個匿名方法的例子改成用lambda表達式實現:
1 namespace DelegateTest
2 {
3 class Program
4 {
5 //創建委托類型
6 delegate int Mydelegate(int x, int y);
7 static void Main(string[] args)
8 {
9 //創建委托實例,指向匿名函數
10 // Mydelegate mydelegate = delegate(int x,int y) { return x + y; };
11
12 //通過委托調用匿名方法
13 // Console.WriteLine(mydelegate(3,2));
14
15 Mydelegate youdelegate = (x, y) => { return (x - y); };
16 Console.WriteLine(youdelegate(3, 2));
17
18 Console.ReadKey();
19 }
20 }
21 }
總結:匿名方法就是沒有名字的函數,Lambda表達式就是匿名方法的簡潔版(指的是用在委托上這方面,Lambda還有其他方面的用處),兩者都只是讓代碼更簡潔,但在更底層層次本質是一樣的