標籤:
最經在學習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還有其他方面的用處),兩者都只是讓代碼更簡潔,但在更底層層次本質是一樣的
C#學習之初步理解委託、事件、匿名方法和Lambda