国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

【C#】事件

2019-11-17 02:58:54
字體:
來源:轉載
供稿:網友

【C#】事件

前言:CLR事件模式建立在委托的基礎上,委托說調用回調方法的一種類型安全的方式。

我個人覺得事件本質就是委托,所以把委托弄清楚,只要知道事件基本語法就會使用了(如果說到線程安全,我個人覺得這個應該和線程一起去討論),所以這篇只做一個簡單的時間介紹和寫一些我看到的或我用到的一些代碼。

EventHandler

  

public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);

  上面是C#的源碼,超簡單有木有(還是委托)。

  有兩個類型:

    1.Object sender :事件源

    2.TEventArgs e :泛型,這里可以自定義事件所需要的額外參數。

  

  既然知道基本的語法,我們來看看怎么寫。

internal sealed 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; } }}
View Code

 這里我們定義另一個類NewMailEventArgs,注意了 這里繼承了EventArgs,所有的事件參數的類都需要繼承這個父類。這里都是我們回調函數所要用的參數。

 internal class MailManager    {        public event EventHandler<NewMailEventArgs> NewMail;        protected virtual void OnNewMail(NewMailEventArgs e)        {            if (NewMail!=null)            NewMail(this, e);        }    }
View Code

這里定義了一個事件NewMail,EventHandler的參數類型是NewMailEventArgs(就是我們自定義的那個參數類),我們慣用的方式在同一個類里面寫調用的方法,以On開頭+事件名結尾,但是這里有一個很危險地方,就是多線程的時候,如果在執行的時候,其他地方正好取消了訂閱呢,又會變成NULL,所以這里可以變成

 

  internal class MailManager    {        public event EventHandler<NewMailEventArgs> NewMail;        protected virtual void OnNewMail(NewMailEventArgs e)        {            e.Raise(this, ref NewMail);        }        public void SimulateNewMail(string from, string to, string subject)        {            var e = new NewMailEventArgs(from, to, subject);            OnNewMail(e);        }    }    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);        }    }
View Code

這里是我習慣用法,也是CLR書上推薦的用法,做一個通用Args的擴展類EventArgExtensions:主要說用于做線程安全和執行回調函數所用(我覺得這樣比較單一,封裝起來,要修改也只要修改一處就好,記住這里是通用的事件調用,所以如果有特殊的需求,請不要加進來,可以在特殊的地方處理),有關Interlocked.CompareExchange可以看下官方的文檔,這個就是用來做輕量級線程同步比較的。

        static void Main(string[] args)        {            var mail = new MailManager();            mail.NewMail += mail_NewMail;            mail.SimulateNewMail("a", "b", "c");            mail.NewMail -= mail_NewMail;            Console.ReadKey();        }        static void mail_NewMail(object sender, NewMailEventArgs e)        {            Console.WriteLine(e.From);            Console.WriteLine(e.To);            Console.WriteLine(e.Subject);        }
View Code

最后我們在Main方法中訂閱事件(mail.NewMail+=mail_NewMail;這里的話直接+=然后按兩個Tab鍵,自己就出來了),取消訂閱用-=。是不是很簡單?到這里基本的事件就已經說完了。

接下來分析一下CLR最后提供一份EventSet代碼(這份代碼也是我的大愛,可以集中管理起來事件,不會讓事件到處亂飛,喜歡的朋友可以研究下,這里就不多做介紹了,提供的代碼還是有不少錯誤,比如空指針,沒有判斷是否存在key之類的情況,不過里面的想法的確值得好好學習)

public sealed class EventKey : Object {}///////////////////////////////////////////////////////////////////////////////public sealed class EventSet {   // The private dictionary used to maintain EventKey -> Delegate mappings   private readonly Dictionary<EventKey, Delegate> m_events =       new Dictionary<EventKey, Delegate>();   // Adds an EventKey -> Delegate mapping if it doesn't exist or    // combines a delegate to an existing EventKey   public void Add(EventKey eventKey, Delegate handler) {      Monitor.Enter(m_events);      Delegate d;      m_events.TryGetValue(eventKey, out d);      m_events[eventKey] = Delegate.Combine(d, handler);      Monitor.Exit(m_events);   }   // Removes a delegate from an EventKey (if it exists) and    // removes the EventKey -> Delegate mapping the last delegate is removed   public void Remove(EventKey eventKey, Delegate handler) {      Monitor.Enter(m_events);      // Call TryGetValue to ensure that an exception is not thrown if      // attempting to remove a delegate from an EventKey not in the set      Delegate d;      if (m_events.TryGetValue(eventKey, out d)) {         d = Delegate.Remove(d, handler);         // If a delegate remains, set the new head else remove the EventKey         if (d != null) m_events[eventKey] = d;         else m_events.Remove(eventKey);      }      Monitor.Exit(m_events);   }   // Raises the event for the indicated EventKey   public void Raise(EventKey eventKey, Object sender, EventArgs e) {      // Don't throw an exception if the EventKey is not in the set      Delegate d;      Monitor.Enter(m_events);      m_events.TryGetValue(eventKey, out d);      Monitor.Exit(m_events);      if (d != null) {         // Because the dictionary can contain several different delegate types,         // it is impossible to construct a type-safe call to the delegate at          // compile time. So, I call the System.Delegate type’s DynamicInvoke          // method, passing it the callback method’s parameters as an array of          // objects. Internally, DynamicInvoke will check the type safety of the          // parameters with the callback method being called and call the method.         // If there is a type mismatch, then DynamicInvoke will throw an exception.         d.DynamicInvoke(new Object[] { sender, e });      }   }}
View Code
public class FooEventArgs : EventArgs { }// Define the EventArgs-derived type for this event.public class BarEventArgs : EventArgs { }///////////////////////////////////////////////////////////////////////////////internal c
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 石嘴山市| 桐梓县| 临朐县| 盐城市| 陕西省| 宁夏| 榕江县| 禹州市| 新平| 阿拉善左旗| 邮箱| 南涧| 西华县| 绩溪县| 兰西县| 台东市| 梓潼县| 大田县| 松桃| 浦北县| 镇巴县| 儋州市| 永善县| 耿马| 廊坊市| 肥西县| 苍梧县| 镇坪县| 临漳县| 勃利县| 兰西县| 安塞县| 平塘县| 全椒县| 察哈| 齐齐哈尔市| 江永县| 城固县| 乌兰浩特市| 南华县| 田林县|