c#委託和lambda表示式(一)
如何使用委託
委託是安全封裝方法的型別,類似於c和c++中的函式指標。與c函式指標不同的是,委託是面向物件的、型別安全的和可靠的。委託型別是由委託的名稱確定。以下是宣告名為Del的委託,該委託可以封裝採用字串作為引數並返回void的方法:
public delegate void Del(string message);
委託物件通常通過提供委託將封裝的方法的名稱或使用匿名的方法構造。對委託進行例項化後,委託會將對其進行的方法呼叫傳遞到該方法。呼叫方法傳遞到為他的引數將傳遞到該方法,並且委託會將方法的返回值返回到呼叫方。這被稱為呼叫委託。例項化的委託可以按封裝的方法本身進行呼叫。
//被委託的方法
public static void delegateMethod(string message)
{
System.Console.WriteLine(message);
}
//委託的構造和呼叫
Del handler = delegateMethod;
handler("Hello World");
由於例項化的委託是一個物件,因此可以作為引數傳遞或者分配給一個屬性。這允許方法作為引數接受委託並在稍後呼叫委託。這被稱於非同步回撥。當使用這種方式使用委託時,使用委託的程式碼不需要知道使用方法的實現方法。
//使用委託作為引數的方法
public void MethodWithCallback (int a, int b, Del callback)
{
callback("The number is :" + (a + b).ToString());
}
//呼叫該方法
MethodWithCallback(1, 2, handler);
當委託構造為封裝例項方法時,委託將同時引用例項和方法。委託不知道除其所封裝方法以外的例項型別,因此委託可以引用任何型別的物件,只要該物件有與委託簽名匹配的方法。當委託構造為靜態方法時,委託僅引用方法。
委託型別派生自.Net Framework中的Delegate類。委託型別是封裝的,他們不能派生出其他類,也不能從Delegate派生出自定義類。
//委託構造方法類
public class MethodClass
{
public void method1(string s);
public void method2(string s)
}
//例項方法構造委託
MethodClass obj = new MethodClass();
Del d1 = obj.method1;
Del d2 = obj.method2;
加上之前顯示的靜態delegateMethod,我們現在已經有3個Del的例項。呼叫委託時,可以呼叫多個方法,這成為多播。方法是想委託列表新增其它方法,使用加法運算子或加法賦值運算子(“+”或”+=”)新增委託。例如:
Del allMethodDelegate = d1 + d2;
allMethodDelegate += handler;
此時allMethodDelegate呼叫列表包含3個方法,呼叫allMethodDelegate時,將順序呼叫所有三個方法。如果委託使用引用引數,引用將按相反的順序傳遞到所有的方法中,並且一種方法進行的任何更改都將在另一種方法上見到。 當方法引發未在方法內捕獲到的異常時,該異常將傳遞到委託的呼叫方,並且不會呼叫呼叫列表中的後續方法。 如果委託具有返回值和/或輸出引數,它將返回上次呼叫方法的返回值和引數。 若要刪除呼叫列表中的方法,請使用減法運算子或減法賦值運算子(“-”或“-=”)。 例如:
allMethodDelegate -= d1;
allMethodDelegate = allMethodDelegate - d2;
多播委託廣泛用於事件處理中。 事件源物件將事件通知傳送到已註冊接收該事件的接收方物件。若要註冊一個事件,接收方需要建立用於處理該事件的方法,然後為該方法建立委託並將委託傳遞到事件源。事件發生時,源呼叫委託。然後,委託將對接收方呼叫事件處理方法,從而提供事件資料。給定事件的委託型別由事件源確定。 有關詳細資訊,請參閱事件(C# 程式設計指南)。
在編譯時比較分配的兩個不同型別的委託將導致編譯錯誤。 如果委託例項是靜態的 System.Delegate 型別,則允許比較,但在執行時將返回 false。 例如:
delegate void Delegate1();
delegate void Delegate2();
static void method(Delegate1 d, Delegate2 e, System.Delegate f)
{
// Compile-time error.
//Console.WriteLine(d == e);
// OK at compile-time. False if the run-time type of f
// is not the same as that of d.
System.Console.WriteLine(d == f);
}
委託的宣告方式
//宣告一個delegate
delegate void Del(string str);
//宣告一個和Del相同簽名的方法
static void notify(string name);
委託例項例項的幾種構造方式:
//使用new例項化一個Del
Del del = new Del(Notify);
//直接賦值
Del del2 = Notify;
//匿名的方式
Del del3 = delegate(string name)
{Console.WriteLine("Notification received for: {0}", name);};
//使用Lambda表示式
Del del4 = name => { Console.WriteLine("Notification received for: {0}", name); };