事件的定義過程 定義類型來容納所有需要發送給事件通知接收者的附加信息 簡單的說,就是調用事件的時候能夠傳遞一些參數信息 定義事件成員 事件成員類型為 ,意味著‘事件通知’的所有接收者都必須提供一個原型和 委托類型相匹配的回調方法, 所以方法原型必須具有以下形式 定義負責引發事件的方法來通知事件的登記 ...
事件的定義過程
定義類型來容納所有需要發送給事件通知接收者的附加信息
簡單的說,就是調用事件的時候能夠傳遞一些參數信息
internal 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; } }
}
定義事件成員
internal class MailManager
{
//事件成員,關鍵字event
public event EventHandler<NewMailEventArgs> NewMail;
}
事件成員類型為EventHandler<NewMailEventArgs>
,意味著‘事件通知’的所有接收者都必須提供一個原型和EventHandler<NewMailEventArgs>
委托類型相匹配的回調方法,
// 表示將處理事件的方法 [Serializable] public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);
所以方法原型必須具有以下形式
//事件模式要求所有方法返回值都是void,因為引發事件後可能會回調好幾個方法,但是沒法獲取所有方法的返回值
void methodname(object sender, NewMailEventArgs e);
定義負責引發事件的方法來通知事件的登記對象
要調用事件時,當前類及其派生類中的代碼會調用該方法。該方法要獲取一個參數(NewMailEventArgs
對象,這個對象中包含了傳給通知接收對象的信息)
internal class MailManager
{
//事件成員關鍵字event
public event EventHandler<NewMailEventArgs> NewMail;
protected virtual void OnNewMail(NewMailEventArgs e) {
//出於線程安全的考慮,現在將對委托欄位的引用複製到一個臨時欄位中
EventHandler<NewMailEventArgs> temp = Interlocked.CompareExchange(ref NewMail, null, null);
if (temp!=null)
{
temp(this, e);
}
//在.Net初期,是建議用以下這種方式的,但是問題在於,當線程發現NewMail不為null,
//然後在調用NewMail(this, e)之前,另一個線程從委托鏈中移除了委托,使NewMail變為了null,
//這樣就引發了空異常,為了避免這個問題,推薦用上面的方式
//if (NewMail != null)
//{
// NewMail(this, e);
//}
}
}
為了方便,我們可以定義一個擴展方法
public static class EventArgsExtensions
{
public static void Raise<TEventArgs>(this TEventArgs e, object sender, ref EventHandler<TEventArgs> handler)
where TEventArgs:EventArgs
{
EventHandler<TEventArgs> temp = Interlocked.CompareExchange(ref handler, null, null);
if (handler!=null)
{
handler(sender, e);
}
}
}
這樣在調用的時候就簡單多了
protected virtual void OnNewMail(NewMailEventArgs e)
{
e.Raise<NewMailEventArgs>(this, ref NewMail);
}
定義方法將輸入轉換為期望事件
internal class MailManager
{
//事件成員關鍵字event
public event EventHandler<NewMailEventArgs> NewMail;
protected virtual void OnNewMail(NewMailEventArgs e)
{
e.Raise<NewMailEventArgs>(this, ref NewMail);
}
//定義一個方法,將輸入轉換為期望事件
public void SimulateNewEmail(string from, string to, string subject)
{
//調用虛方法通知對象事件已發生
//如果沒有類重寫該方法,我們的對象通知事件的所有登記對象
OnNewMail(new NewMailEventArgs(from, to, subject));
}
}
設計偵聽事件的類型
internal sealed class Fax
{
public Fax(MailManager m)
{
//向MailManager的NewMail事件登記我們的回調方式
m.NewMail += m_NewMail;
}
void m_NewMail(object sender, NewMailEventArgs e)
{
Console.WriteLine("Faxing mail message:");
Console.WriteLine(" From:{0},to:{1},Subject:{2}",e.From,e.To,e.Subject);
}
//執行這個方法,Fax對象將取消對NewMail事件的關註
public void Unregister(MailManager m)
{
m.NewMail -= m_NewMail;
}
}