文章出處

事件的定義過程

定義類型來容納所有需要發送給事件通知接收者的附加信息

簡單的說,就是調用事件的時候能夠傳遞一些參數信息

    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;
        }
    }

文章列表




Avast logo

Avast 防毒軟體已檢查此封電子郵件的病毒。
www.avast.com


arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()