事件:定義了事件成員的類允許通知其他其他物件發生了特定的事情。具體的說,定義了事件成員的類能提供以下功能
1.方法能登記它對事件的關注
2.方法能登出它對事件的關注
3.事件發生時,登記了的方法將收到通知
型別之所以能提供事件通知功能,是因為型別維護了一個已登記方法的列表。事件發生後,型別將通知列表中所有已登記的方法。
事件是以委託為基礎。委託是呼叫回撥方法的一種型別安全的方式。物件憑藉回撥方法接收他們訂閱的通知。
假如有一下場景:要設計一個電子郵件程式。當有新的郵件的到達時,使用者希望做些一別的操作,例如轉發給其他人或其他想實現的功能。事件在其中起到的就是一個通知的作用,告訴其他物件有新的郵件到達了,可以做XXX事情了。
下面使用事件實現這個功能
1.定義一個附加資訊類,用來通知接收者發生了什麼。
////// 事件附加訊息 ///public class NewMailEventArgs:EventArgs{ private readonly string m_from,m_to,m_subject; public NewMailEventArgs(string from,string to,string subject){ m_from=from; m_to=to; m_subject=subject; } // 發件人 public string From { get{return m_from;} } // 接收人 public string To { get{return m_to;} } // 主題 public string Subject{get{return m_subject;}} }
附加資訊類繼承了EventArgs,這個基類只定義了一個空的資訊,在沒有附加資訊時可直接使用EventArgs.Empty。EventArgs類的原始碼
namespace System { // // Summary: // Represents the base class for classes that contain event data, and provides a // value to use for events that do not include event data. public class EventArgs { // // Summary: // Provides a value to use with events that do not have event data. public static readonly EventArgs Empty; // // Summary: // Initializes a new instance of the System.EventArgs class. public EventArgs(); } }
2.定義事件成員
事件成員使用C#關鍵字event定義。每個事件成員都要指定以下內容:可訪問識別符號public(因為只有publi才能使其他物件訪問),委託型別以及名稱。
public class MailManager{ // 定義事件成員 public event EventHandlerNewMail; }
它的型別是EventHandler
namespace System { // // Summary: // Represents the method that will handle an event when the event provides data. // // Parameters: // sender: // The source of the event. // // e: // An object that contains the event data. // // Type parameters: // TEventArgs: // The type of the event data generated by the event. public delegate void EventHandler(object sender, TEventArgs e); }
所以接收者必須提供的方法必須是一下形式:
void MethodName(Object sender,NewMailEventArgs e);
3. 定義負責引發事件的方法來通知事件的登記物件
public class MailManager{ // 定義事件成員 public event EventHandlerNewMail; // 定義負責引發事件的方法來通知已登記的物件 protected virtual void OnNewMail(NewMailEventArgs e){ // 將欄位複製到一個臨時變數,避免多執行緒情況中這個成員被移除 EventHandlertemp=Volatile.Read(ref NewMail); if(temp!=null) temp(this,e); } // 接受附加資訊並呼叫引發事件的方法來通知所有登記的物件 public void SimulateNewMail(string from,string to,string subject){ NewMailEventArgs e=new NewMailEventArgs(from,to,subject); OnNewMail(e); } }
4. 定義事件接收者
public class Fax{ public Fax(MailManager mm){ // 構造委託例項,向事件登記回撥方法 mm.NewMail+=FaxMsg; } ////// 回撥方法 //////表示MailManager物件,便於將資訊傳遞給他///表示MailManager物件想傳給我們的附加資訊private void FaxMsg(object sender,NewMailEventArgs e){ Console.WriteLine("msg:{0},{1},{2}",e.From,e.To,e.Subject); } ////// 登出對事件的登記 //////public void Unregister(MailManager mm){ mm.NewMail-=FaxMsg; } }
物件不在接收事件通知時應登出對事件的關注。因為物件只要向事件等急了它的一個方法,便不能被垃圾回收。
5. 程式初始化時應首先構造MailManager物件,將指向它的變數傳遞給Fax。在Fax構造器中新增對事件的關注。最後呼叫MailManager物件的事件通知方法
static void Main(string[] args) { MailManager mm=new MailManager(); Fax f=new Fax(mm); mm.SimulateNewMail("a","b","Hello World!"); Console.ReadKey(); }
控制檯輸出結果:以呼叫回撥方法。
[ml5rwbikls ] 詳解C#之事件已經有354次圍觀