委托是一種定義方法的類,這樣就可以使得方法A,可以像string類、int類一樣當做方法B的參數進行傳遞。這種將方法動態地賦值給參數的做法,可以避免在代碼中大量使用if-else(or switch)語句,同時使得程序具有更好的可擴展性。委托被大量使用在WPF中(至少我是這么認為的)。但是委托類不同於string類和int類的區別在於,可以將多個方法賦給同一個委托,或者說多個方法可以綁定到同一個委托類上,當調用該委托時,將依次調用其所綁定的方法,但是string類和int類,后面綁定的參數將會替換掉前一個參數。
事件用於封裝委托類。當使用string類時,可以通過屬性對字段進行封裝,某個string類可以只讀的,也可以是只寫的。使用event關鍵字,聲明一個事件也就是聲明了一個進行了封裝的委托類型變量,比如下面這條代碼:
public event PropertyChangedEventHandler PropertyChanged;
其中,PropertyChangedEventHandler是一個委托類,event關鍵字定義了一個封裝該委托的PropertyChanged事件。事件封裝了委托,那么就可以將方法注冊到事件中,當事件發生時,會依次調用注冊了該事件的方法。比如在WPF中,給一個button控件添加Click方法,其實就是將Btn_Click方法注冊到button控件的Click事件中,即button.Click += Btn_Click.
.NET Framework中對委托和事件編寫的規范:
-
委托類型的名稱都應該以EventHandler結尾;
-
委托的返回值是void(最好),並接受兩個輸入參數,一個是Object類,一個EventArgs類(或繼承自EventArgs);
-
事件的命名為委托去掉EventHandler之后剩余的部分;
-
繼承自EventArgs的類型應該以EventArgs結尾;
-
訂閱事件的方法命名,通常為On+事件名。
Example:這個例子來源於張子陽博客中的例子,我最開始學習委托和事件也是看了這篇博客,所以我的這篇文章算是學習了委托和事件之后的一個整理,目的是加深自己的記憶。張子陽的博客地址如下:
http://www.tracefact.net/tech/009.html
http://www.tracefact.net/tech/029.html
例子是這樣的,假設有一台熱水器,當加熱到指定溫度時會提醒用戶,則有一個加熱方法,還有一個提醒方法。提醒方法要注冊加熱事件,當溫度達到指定值時,調用提醒方法。
Heater類
public class Heater { private int temperature; // 定義一個名為BoiledEventHandler的委托類,兩個參數,一個object類,一個是繼承自EventArgs類的BoiledEventArgs類 public delegate void BoiledEventHandler(object sender, BoiledEventArgs e); // 定義一個封裝BoiledEventHandler委托的事件 public event BoiledEventHandler Boiled; // 訂閱Boiled事件的方法 protected virtual void OnBoiled(BoiledEventArgs e) { // 如果有方法注冊了該事件,則調用所有注冊了該事件的方法 if (Boiled != null) Boiled(this, e); } // Heater類中有一個加熱的方法 public void BoilWater() { for (int i = 0; i <= 100; i++) { temperature = i; if (i % 10 == 0 && i <=95) Console.WriteLine("Temperature is {0}.", i); if(temperature > 95) { BoiledEventArgs e = new BoiledEventArgs(temperature); OnBoiled(e); } } } }
Alarm類
public class Alarm { public void MakeAlert(object sender, BoiledEventArgs e) { Heater heater = sender as Heater; Console.WriteLine("Alarm : Temperature is {0}.", e.temperature); } }
客戶端程序
class Program { static void Main(string[] args) { Heater heater = new Heater(); Alarm alarm = new Alarm(); // 將Alarm中的MakeAlert方法注冊到Heater的Boiled事件中 heater.Boiled += alarm.MakeAlert; heater.BoilWater(); Console.Read(); } }
源代碼github地址: