Function pointer(函數指標)
在C/C++ 若要設計事件(Callback function), 可利用function pointer來完成, 其詳細作法可參考Callback FunctionDelegate(委託)
delegate是C#特殊的類別, 它可以封裝一個函數, 但與一般類別不同之處,delegate擁有一個簽名(可以代表函式的引數類型和回傳值類型). delegate實現的功能和C/C++中的函數指標十分相似.
C/C++ :
void (*UpdateCallback)(double time);
C# : delegate是C#特殊的類別, 它可以封裝一個函數, 但與一般類別不同之處,delegate擁有一個簽名(可以代表函式的引數類型和回傳值類型). delegate實現的功能和C/C++中的函數指標十分相似.
C/C++ :
void (*UpdateCallback)(double time);
delegate void UpateDelegate(double time);
雖然delegate類似於函式指標(function pointer), 不過還是有很多不同之處, 例如delegate具有物件導向和型別安全等特性.
delegate用法
delegate的使用步驟如下:
delegate的使用步驟如下:
宣告一個delegate的型別, 每個delegate型別封裝了函數的回傳類型,引數的數目, 和引數的類型, 如下面陳述式所示:
delegate void MessageDelegate(string str);
public static void HelloFun(string str) { Console.WriteLine(" Hello, {0}!", str); } public static void GoodbyeFun (string str) { Console.WriteLine(" Goodbye, {0}!", str); }
3. 建立委派物件, 並指定委派方法
delegate宣告後, 必須再將它實體化才能使用(和一般類別的使用方式一樣, 需先將物件實體化), 並指定所代表的函式, 但不需傳入引數, 如下面範例所示
static void Main(string[] args) { MessageDelegate msDelegate = new MessageDelegate(HelloFun); }
delegate同時也支援多點傳送(+=, -=), 因為繼承自System.MulticastDelegate類別, 你可以使用+= 運算子將多個方法綁定到同一個delegate, 當呼叫這個delegate的時候, 將依次呼叫其所綁定的方法. 當然你也可以使用 - = 運算子 將某個委派參考從委派清單中移除.
MessageDelegate msDelegate; msDelegate = new MessageDelegate(HelloFun); msDelegate += new MessageDelegate(GoodbyeFun); msDelegate -= new MessageDelegate(HelloFun);
4. 透過委派物件執行委派方法
如下所示:
msDelegate("Peter"); //等同msDelegate.invoke("Peter");
event
event的出現,是要避免使用delegate可能會破壞物件封裝性的問題,主要有下面兩點:
1. delegate 可以隨意進行賦值操作, 若不小心使用將會移除所有委派
2. 為了讓delegate可以綁定特定的方法, 宣告時必須定義成public屬性, 但也因此破壞掉物件的封裝性, 因為類別的內外都可以呼叫delegate
考慮下面例子:
public class ButtonControl { public delegate void ClickDelgate(object sender, EventArgs e); public ClickDelgate ClickEvent; public void OnFire(EventArgs e) { ClickEvent(this, e); } } static public void TexboxUpdate(object sender, EventArgs e) { Console.WriteLine("Texbox update by button click"); } static public void LabelUpdate(object sender, EventArgs e) { Console.WriteLine("Label update by button click"); } static void Main(string[] args) { ButtonControl btnCtrl = new ButtonControl(); btnCtrl.ClickEvent = new ButtonControl.ClickDelgate(TexboxUpdate); btnCtrl.ClickEvent += new ButtonControl.ClickDelgate(LabelUpdate); btnCtrl.ClickEvent = null; //這將會移除所有委派 btnCtrl.ClickEvent(null, new EventArgs()); //不應該讓使用者可以呼叫 }
而就觀察者模式來說, 也應避免下面這些情況:
- 對於客戶端(觀察者), 應該只適合透過註冊/取消來操作自己對應的事件, 不應該隨意進行的賦值操作, 如果不小心將發佈者的delegate類別直接賦值null, 將會取消掉發佈者所有的通知列表
- 發佈事件的通知應該由發佈者來觸發, 不應該讓客戶端可以呼叫
因此C#利用event來封裝delegate類型的變數, 所以在類別的外部, 使用者只能透過註冊“+=”和取消“-=” 來作事件的操作.
Event使用範例
將上述範例中, public ClickDelgate ClickEvent 加上 event修飾字
public class ButtonControl { public delegate void ClickDelgate(object sender, EventArgs e); public event ClickDelgate ClickEvent; public void OnFire(EventArgs e) { if (ClickEvent != null) ClickEvent(this, e); } } static void Main(string[] args) { ButtonControl btnCtrl = new ButtonControl(); //只能使用+=,-= 來對事件操作 btnCtrl.ClickEvent += new ButtonControl.ClickDelgate(TexboxUpdate); btnCtrl.ClickEvent += new ButtonControl.ClickDelgate(LabelUpdate); }
EventHandler
雖然 C# 語言允許event使用任一種delegate型別,但是 .NET Framework 對於使用於event的delegate型別有更嚴格的規範, 因此另外定義出一個適當的delegate型別EventHandler, 語法如下:
public delegate void EventHandler(object sender, EventArgs e);
EventHandler 為預先定義的delegate, EventHandler會定義一個沒有傳回值的方法, 方法第一個參數的型別為 object, 表示引發事件的執行個體(如果是button1的click事件, 則sender就是button1), 而第二個參數的型別為EventArgs, 表示封裝事件的額外資訊.
EventHandler使用範例
public class ButtonControl { //利用EventHandler取代delegate void EventHandler(object sender, EventArgs e) public event EventHandler ClickEventHandler; public void OnClick() { if (ClickEventHandler != null) { ClickEventHandler(this, new EventArgs()); } } }
自訂EventArgs
在.NET Framework 2.0時引進EventHandler泛型版本,即 EventHandler<T>也就是如果你要自訂的 EventArgs 類別, 可以參考下面範例:
public event EventHandler<customeventargs> RaiseCustomEvent; public class CustomEventArgs : EventArgs { public CustomEventArgs(string s) { msg = s; } private string msg; public string Message { get { return msg; } } }
參考資料:
發行符合 .NET Framework 方針的事件
委派教學課程
事件教學課程
函數指標的進化論(下)
我對.NET中delegate和event區别的理解
談談委派 (Delegate)
C# 筆記:重訪委派-從 C# 1.0 到 2.0 到 3.0
沒有留言:
張貼留言