C# 委託,事件和Lambda表示式 (轉)
關於這個論題,
Delegates, Events, and Lambda Expressions 對此有比較深入的分析,可以參考。
C# vs C++之一:委託 vs 函式指標 比較了委託和C++指標的區別。
.NET 中的委託確實和C/C++的函式指標非常相似。它是一個值型別,它包裝了一個指向方法的引用。它的作用也是為了能夠將方法和變數一樣作為引數傳遞。委託的典型應用是控制元件的事件處理方法。很顯然,一個控制元件在設計的時候沒有辦法知道當特定事件發生的時候,需要什麼方法來處理,這就需要將方法作為引數傳遞給控制元件。在LINQ中,也大量用到了委託。
宣告一個委託要使用delegate關鍵字,如下:
delegate int Echo(string message);
這句程式碼宣告瞭一個委託型別,這個委託型別的例項可以接受引數為string,返回值為int型的函式。這個方法可以是物件的方法,也可以靜態方法,還可以是匿名方法,只要方法的簽名和返回值是和宣告一致的。這和C的函式指標很像,但是函式指標僅僅包含函式入口地址,而委託是一個型別,它具有比函式指標更強的功能。其中一點就是當方法是例項方法的時候,這個方法可以獲得物件的其他變數的值,文首的第二篇文章對此有詳細介紹,不再贅述。第二點就是委託是支援多播的,也就是一串方法可以可以依次被執行。例如:
static int EchoOriginal(string message) { Console.WriteLine(message); return 1; } static int EchoReverse(string message) { StringBuilder sb=new StringBuilder(); for(int i=message.Length-1;i>=0;i--) sb.Append(message[i]); Console.WriteLine(sb.ToString()); return -1; } static void Main(string[] args) { Echo eo = EchoOriginal; Echo er = EchoReverse; Echo all = eo + er; eo("Hello world"); int i=all("Hello Delegate"); Console.WriteLine(i); }
我們定義兩個方法,這兩個方法都符合Echo的宣告,最後Echo的all例項可以接受兩個委託,呼叫all的時候,eo,er會被一次釣魚,返回值是最後一個委託的返回值。程式的輸出是:
Hello world
Hello Delegate
etageleD olleH
-1
事實上,方法並不需要和委託宣告型別的簽名完全一致,.net允許方法的返回值是繼承自宣告的返回值的型別,方法的引數型別是宣告的引數的父型別。這就是Covariance and Contravariance in Delegates.
.NET的事件機制是以委託為基礎的。事件機制有兩部分組成,一部分是事件釋出者,一部分是事件響應者。其實現原理就是由事件釋出者宣告一個委託物件,由事件響應者向那個委託掛載具體的處理方法,事件釋出者在需要的時候呼叫這個委託,這樣響應者的程式碼就會被執行。事實上,.NET也是這麼做的。C#的event關鍵字就僅僅做了少量的工作,其中包括為類生成一個私有的delegate. event所支援的委託是有限制的委託,它的返回值必須是void,引數是兩個,第一個是事件發生者,第二個引數是事件需要攜帶的引數。最簡單的事件處理委託.net已經宣告瞭:
public delegate void EventHandler( Object sender, EventArgs e )
宣告事件的基本方式是 event 委託型別 事件名稱;
舉個例子,有這樣的類,每當找到一個奇數,他就會觸發一個事件。我們的程式在接到這個事件的時候在螢幕輸出一個提示。類的程式碼可以這樣實現:
public class OddFinder { public event EventHandler FindOdd; public void Find(int from, int to) { for (int i = from; i <= to; i++) { if (i % 2 != 0) if (FindOdd != null) FindOdd(this, EventArgs.Empty); } } }
這個類很簡單,展示了發起事件的基本方法。首先宣告一個事件,指明這個事件處理函式的委託型別。在需要觸發事件的時候,首先判斷是否有事件處理函式掛載,然後呼叫這個委託即可。外部處理程式把事件處理程式掛載上去:
static void Main(string[] args) { OddFinder f = new OddFinder(); f.FindOdd += new EventHandler(f_FindOdd); f.Find(1, 5); } static void f_FindOdd(object sender, EventArgs e) { Console.WriteLine("Found!"); }
這樣程式執行後,就會在螢幕上輸出3次Found!。如果需要在觸發事件的時候,傳遞更多的資訊給事件處理函式,比如當前找到的奇數是多少,那麼就需要新建一個類繼承自EventArgs,在這個類中可以新增一些需要的資料。 再宣告一個委託,第二個引數為EventArgs型別即可。
以上是基本的委託和事件的介紹,自.net 1.0開始就是如此,.net 2.0 引入了匿名方法,可以簡化委託的某些操作。例如:
f.FindOdd += delegate(object sender, EventArgs e) { Console.WriteLine("Found!"); };
匿名方法使用delegate關鍵字加上參數列,最後是程式碼塊來定義。它可以作為委託賦值給委託型別。它可以省去單獨定義一個方法的麻煩。
.net 3.0之後引入了Lambda表示式,它進一步簡化了匿名方法的寫法,使得在C#中,把函式作為引數傳遞變得更加簡單自然,從而C#變得更加具有函式式語言的味道。關於函式式語言的進一步介紹,可以參考:Functional Programming Languages . 函式式語言的理論基礎是Lambda Calulus,關於此可以參考A Tutorial Introduction to the Lambda Calculus .
Lambda表示式本質上還是匿名方法,它的一般形式是:
(input parameters) => expression
左側是引數列表,=>右側是方法體,可以是一個表示式(expression lambda),也可以是大括號括起來的語句段(statement lambda)。它省略了delegate關鍵字,使得程式碼更加緊湊。例如:
n=>n%2==0;
等價於
delegate(int n){ return n%2==0;}
expression lambda 廣泛應用於LINQ,它可以用來構造Expression Tree,Expression Tree是LINQ的基礎。可以通過動態構造Expression Tree來實現複雜的動態LINQ查詢,不過這種方法雖然通用,對於資料庫查詢,使用起來和傳統的拼接字串相比還是很麻煩。下文將介紹微軟的一個LINQ擴充套件,Dynamic LINQ.
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12639172/viewspace-674282/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- .NET委託,事件和Lambda表示式事件
- C# 委託(delegate)、泛型委託和Lambda表示式C#泛型
- 委託、Lambda表示式、事件系列03,從委託到Lamda表示式事件
- 委託、Lambda表示式、事件系列07,使用EventHandler委託事件
- 委託、Lambda表示式、事件系列05,Action委託與閉包事件
- C#中的委託,匿名方法和Lambda表示式C#
- C#快速入門教程(17)—— 委託、事件與Lambda表示式C#事件
- 委託、Lambda表示式、事件系列02,什麼時候該用委託事件
- 委託、Lambda表示式、事件系列01,委託是什麼,委託的基本用法,委託的Method和Target屬性事件
- 用 Lambda表示式傳遞委託
- 委託、Lambda表示式、事件系列06,使用Action實現觀察者模式,體驗委託和事件的區別事件模式
- 五分鐘重溫C#委託,匿名方法,Lambda,泛型委託,表示式樹C#泛型
- c# 委託和事件C#事件
- 委託、Lambda表示式、事件系列04,委託鏈是怎樣形成的, 多播委託, 呼叫委託鏈方法,委託鏈異常處理事件
- 五分鐘重溫委託,匿名方法,Lambda,泛型委託,表示式樹泛型
- 【UNITY3D 遊戲開發之七】C# 中的委託、事件、匿名函式、Lambda 表示式Unity3D遊戲開發C#事件函式
- C# 事件委託C#事件
- C# 委託事件C#事件
- C# 自定義事件和委託(精彩轉載)C#事件
- C#:委託和自定義事件C#事件
- C# 中的委託和事件C#事件
- C#委託與事件C#事件
- C# 事件 vs 委託C#事件
- C# - 委託與事件C#事件
- 詳解C#委託和事件(一)C#事件
- 詳解C#委託和事件(二)C#事件
- C#中的委託和事件(續)C#事件
- C# 之委託與事件C#事件
- 事件模型和事件委託事件模型
- C#中的Lambda表示式和表示式樹C#
- JS事件流和事件委託JS事件
- 詳解C#委託與事件C#事件
- 詳解C#委託,事件與回撥函式C#事件函式
- 事件委託事件
- C# 委託原理刨析,外加和事件對比C#事件
- C#中的委託和事件-拋磚引玉C#事件
- 委託、事件--委託例項篇事件
- .net的委託和事件的直接理解 (轉)事件