C Sharp/Delegates and Events
介紹
編輯委託(delegate)與事件(event)是Windows或Web應用程式的基礎。委託基本上相當於C語言的函數指針;委託數據告訴C#一個事件被觸發時哪些方法被調用。事件是.NET framework通知某個動作發生了;事件包含了特定信息,如鼠標點擊事件包含了哪個鼠標按鍵在窗體的哪裏被點擊。
委託
編輯委託是一個結構,可引用一個方法,該方法以後可被調用。一個委託的聲明指示特定的方法簽名。一個或更多個方法的引用可以增添到一個委託實例上。委託實例可以被調用,實際上是該委託實例引用的所有方法按照加入該委託的次序被調用。一個簡單例子:
using System;
delegate void Procedure();
class DelegateDemo
{
public static void Method1()
{
Console.WriteLine("Method 1");
}
public static void Method2()
{
Console.WriteLine("Method 2");
}
public void Method3()
{
Console.WriteLine("Method 3");
}
static void Main()
{
Procedure someProcs = null;
someProcs += new Procedure(DelegateDemo.Method1);
someProcs += new Procedure(Method2); // Example with omitted class name
DelegateDemo demo = new DelegateDemo();
someProcs += new Procedure(demo.Method3);
someProcs();
}
}
上例中,delegate void Procedure();
是一個委託的聲明,該語句是完全抽象,不會產生可執行代碼,僅僅是聲明Procedure
為一個無參、返回為空的委託類型。
已被委託引用的方法可以刪除引用:
someProcs -= new Procedure(DelegateDemo.Method1);
從C# 2.0,增加或刪除方法引用可用更簡明的語法:
someProcs += DelegateDemo.Method1;
someProcs -= DelegateDemo.Method1;
調用一個沒有引用任何方法的委託,導致NullReferenceException。
注意,如果委託返回特定類型的結果,那麼調用一個引用了多個方法的委託,實際返回的是最後被執行的方法的結果。
匿名委託
編輯匿名委託是使用delegate關鍵字寫出委託的代碼,可以捕獲局部變量,被編譯器自動轉化為方法。例如:
using System;
delegate void Procedure();
class DelegateDemo2
{
static Procedure someProcs = null;
private static void AddProc()
{
int variable = 100;
someProcs += new Procedure(delegate
{
Console.WriteLine(variable);
});
}
static void Main()
{
someProcs += new Procedure(delegate { Console.WriteLine("test"); });
AddProc();
someProcs();
Console.ReadKey();
}
}
可以如普通方法一樣接受參數:
using System;
delegate void Procedure(string text);
class DelegateDemo3
{
static Procedure someProcs = null;
private static void AddProc()
{
int variable = 100;
someProcs += new Procedure(delegate(string text)
{
Console.WriteLine(text + ", " + variable.ToString());
});
}
static void Main()
{
someProcs += new Procedure(delegate(string text) { Console.WriteLine(text); });
AddProc();
someProcs("testing");
Console.ReadKey();
}
}
輸出為:
testing testing, 100
Lambda表達式
編輯Lambda表達式是比匿名委託更為清晰的方式。語法為:
(type1 arg1, type2 arg2, ...) => expression
這等價於:
delegate(type1 arg1, type2 arg2, ...)
{
return expression;
}
如果只有一個參數,則圓括號可省略。參數類型也可以省略,讓編譯去去推導。例如:
Func<string, int> myFunc = str => int.Parse(str);
這等效於:
Func<string, int> myFunc = delegate(string str)
{
return int.Parse(str);
};
事件
編輯事件是一種特殊的委託,用於事件驅動編程。事件可以是類從成員,但即使其訪問指示符是public,事件只能在包含它的類中被調用,但在其它類可以為事件增加或減少方法引用。例如:
public delegate void ButtonClickedHandler();
class Button
{
public event ButtonClickedHandler ButtonClicked;
ButtonClicked += ()=>{Console.WriteLine("click simulation !")};
public void SimulateClick()
{
if (ButtonClicked != null)
{
ButtonClicked();
}
}
...
}
在其它類中的方法可以通過向該事件委託增加方法,來訂閱到該事件:
Button b = new Button();
b.ButtonClicked += ButtonClickHandler;
private void ButtonClickHandler()
{
//Handle the event
}
即使這個事件被聲明為public,它之惡能在包含它的類中被直接fire。