日本好好热aⅴ|国产99视频精品免费观看|日本成人aV在线|久热香蕉国产在线

  • <cite id="ikgdy"><table id="ikgdy"></table></cite>
    1. 西西軟件園多重安全檢測下載網(wǎng)站、值得信賴的軟件下載站!
      軟件
      軟件
      文章
      搜索

      首頁編程開發(fā)C#.NET → C#事件具體實現(xiàn)步驟

      C#事件具體實現(xiàn)步驟

      相關(guān)軟件相關(guān)文章發(fā)表評論 來源:百度搜索時間:2012/11/14 22:49:15字體大。A-A+

      作者:西西點擊:948次評論:0次標(biāo)簽: 事件

      • 類型:生活服務(wù)大。4.1M語言:中文 評分:10.0
      • 標(biāo)簽:
      立即下載

      定義一個事件成員,表示該類型提供了如下功能:

      1.能夠在事件中注冊方法 2.能夠在事件中注銷方法 3.當(dāng)事件發(fā)生時,注冊的方法會被通知

      (事件內(nèi)部維護(hù)了一個注冊方法列表)

      CLR的事件模型是基于委托的,它可以通過類型安全的方式調(diào)用回調(diào)方法。而回調(diào)方法是訂閱事件的對象接收通知的方式。通過一個例子來說明:

      ①Fax對象的方法注冊到MailManager事件 ②Pager對象的方法注冊到MailManager事件 ③新的郵件到達(dá)MailManager ④MailManager對象向注冊的方法發(fā)出通知,接收通知的方法可以隨意處理。

      具體實現(xiàn)步驟如下:

      1.定義一個類型,能夠hold住任何發(fā)送到事件通知接收者的信息

      當(dāng)一個事件被觸發(fā),觸發(fā)事件的對象可能希望發(fā)送一些額外的信息給事件通知的接收對象。這些額外的信息需要封裝在它自己的類中,根據(jù)約定該類需要從System.EventArgs類派生,并且命名以EventArgs結(jié)尾。這里定義一個NewMailEventArgs類:


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



      關(guān)于EventArgs


      [ComVisible(true)]
      [Serializable]
      public class EventArgs
      {
          public readonly static EventArgs Empty;
      
          static EventArgs()
          {
              EventArgs.Empty = new EventArgs();
          }
      
          public EventArgs()
          {
          }
      }


      這個類沒有實際的用途,只是作為一個基類讓其他對象繼承。很多對象不需要傳遞額外的信息,例如按鈕事件,只是調(diào)用一個回調(diào)方法就夠了。當(dāng)我們定義的事件不需要傳遞額外的信息時,這時調(diào)用EventArgs.Empty就行了,不需要重新構(gòu)建一個EventArgs對象。

      2.定義事件成員

          public class MailManager
          {
              ...
              //NewMail事件名,
              //EventHanlder<NewMailEventArgs>,所有的事件通知接收對象必須提供給該委托類型匹配的回調(diào)方法
              public event EventHandler<NewMailEventArgs> NewMail;
          }


      System.EventHandler委托的定義為:public delegate void EventHandler<TEventArgs>(Object sender, TEventArgs e) where TEventArgs: EventArgs;

      為什么這里第一個參數(shù)sender的類型是Object?畢竟MailManager類型是唯一觸發(fā)這個事件的,所以可以設(shè)計成這樣:
      void MethodName(MailManager sender,NewMailEventArgs e)
      這種情況會有一個弊端,當(dāng)sender是SmtpMailManager時,回調(diào)方法也需要改變,使用Object能夠很好的兼容。定義回調(diào)方法的參數(shù)名約定為e,這樣做主要是為了保持一致性。方便開發(fā)人員。

      事件機(jī)制要求所有的事件處理方法必須返回void,這是必要的,因為一個事件可能觸發(fā)很多的回調(diào)方法,沒有辦法獲取所有的返回值,索性就不允許返回值,全部為void。有些FCL里面的事件處理程序沒有遵循,而是返回了一個Assembly類型。

      3.定義一個方法來響應(yīng)事件的發(fā)生

      按照慣例,這個類應(yīng)該定義一個protected,virtual的方法供內(nèi)部的代碼調(diào)用。這個方法接收一個NewMailEventArgs對象,這個對象包含要傳遞給消息接收方的一些信息。如下:

              protected virtual void OnNewMail(NewMailEventArgs e)
              {
                  //復(fù)制一個委托的引用到臨時字段temp,這樣確保線程安全
                  EventHandler<NewMailEventArgs> temp = Interlocked.CompareExchange(ref NewMail, null, null);

                  //任何注冊到事件里面的方法,通知它們
                  if (temp != null)
                  {
                      temp(this, e);
                  }
              }


      Tips:使用線程安全的方式觸發(fā)事件(①——>④為不斷改進(jìn)的過程)

      ①當(dāng).NET第一次推出的時候,給開發(fā)者推薦的事件觸發(fā)方式如下:

      //v1.0
      protected virtual void OnNewMail(NewMailEventArgs e)
      {
           if (NewMail != null)
           {
                NewMail(this, e);   
           } 
      }


      弊端:這里檢查了NewMail不為null才觸發(fā),但是當(dāng)檢查完之后,在調(diào)用NewMail之前,有其他的線程從委托鏈中移除了一個委托,使得NewMail為null,此時會拋出異常。

      ②先將NewMail用一個臨時變量存起來,這時就不會因為調(diào)用時被其他線程修改而拋出異常。之所以能夠這樣做,是因為委托類型跟字符串類型一樣是不可變的。

      //v2.0
      protected void OnNewMail(NewMailEventArgs e)

           EventHandler<NewMailEventArgs> temp = NewMail;
           if (temp != null)
           {
                temp(this, e); 
           } 
      }


      弊端:可能被編譯器優(yōu)化掉本地temp變量,如果發(fā)生這種情況,就回到了第一種了。

      ③修復(fù)上面的bug,如下:

      //v3.0
      protected void OnNewMail(NewMailEventArgs e)

            EventHandler<NewMailEventArgs> temp = Thread.VolatileRead(ref NewMail);
            if (temp != null)
            {
                 temp(this, e);
            }
      }


      這里使用VolatileRead會強制讀取temp的值,但是這里不能這樣寫,編譯不通過。但是有一個Interlocked.CompareExchange可以使用:

              //v4.0       
              protected virtual void OnNewMail(NewMailEventArgs e)
              {
                  //復(fù)制一個委托的引用到臨時字段temp,這樣確保線程安全
                  EventHandler<NewMailEventArgs> temp = Interlocked.CompareExchange(ref NewMail, null, null);

                  //任何注冊到事件里面的方法,通知它們
                  if (temp != null)
                  {
                      temp(this, e);
                  }
              }


      如果NewMail為null,CompareExchange將NewMail的值改變?yōu)閚ull,如果不為null則返回原值。換句話說,CompareExchange不會改變NewMail的值,只是以線程安全的方式返回NewMail的值,這里是一個原子操作。

      第④個版本是最佳的,技術(shù)上最正確的版本。實際開發(fā)中還是可以使用第②個版本,因為JIT編譯器能夠識別這種模式而不去優(yōu)化本地的temp變量。特別地,所有微軟的JIT編譯器都遵循不會對堆引入新的讀取,因此緩存一個引用在本地變量可以確保堆引用只被訪問一次(這是沒有寫入文檔的,理論上,還是可能發(fā)生變化,所以最好選用第④版本。)

      為了方便可以定義一個擴(kuò)展方法來封裝:

          public static class EventArgExtensions
          {
              public static void Raise<TEventArgs>(this TEventArgs e, Object sender, ref EventHandler<TEventArgs> eventDelegate)
      where TEventArgs : EventArgs
              {
                  EventHandler<TEventArgs> temp = Interlocked.CompareExchange(ref eventDelegate, null, null);
                  if (temp != null)
                  {
                      temp(sender, e);
                  }
              }
          }


      然后可以重寫OnNewMail:

              protected virtual void OnNewMail(NewMailEventArgs e)
              {
                   e.Raise(this, ref NewMail);
              }


      4.定義一個方法用來傳遞一些輸入到事件

              public void SimulateNewMail(String from, String to, String subject)
              {
                  NewMailEventArgs e = new NewMailEventArgs(from, to, subject);
                  OnNewMail(e);
              }
                                  
              

        相關(guān)評論

        閱讀本文后您有什么感想? 已有人給出評價!

        • 8 喜歡喜歡
        • 3 頂
        • 1 難過難過
        • 5 囧
        • 3 圍觀圍觀
        • 2 無聊無聊

        熱門評論

        最新評論

        發(fā)表評論 查看所有評論(0)

        昵稱:
        表情: 高興 可 汗 我不要 害羞 好 下下下 送花 屎 親親
        字?jǐn)?shù): 0/500 (您的評論需要經(jīng)過審核才能顯示)