zoukankan      html  css  js  c++  java
  • 事件,不知道你是否有也这样理解

    目录

    • 事件的特点。
    • 邮件实例及编译器如何对待事件
    • 总结

    一、事件

    public event EventHandler<NewMailInfo> NewMail; 
    • public    其他类可以根据规则进行注册和注销。
    • event     我觉得就是一种标识符,编译器可以进行识别,进而生成相关事件代码。
    • EventHander   泛型委托
      public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);

       

    事件是类的成员,它的出现给类提供了一种能力—-通知其他对象发生了什么。

    事件是一种特殊的委托。其他对象符合规则的方法可以注册和注销事件的关注。 

    二、邮件实例

    需求:当收到新邮件时,同时通知转发给传真机以及其他机器,使得他们可以根据自己的方式处理新邮件 

    1、邮件信息类:承载邮件相关信息,继承EventArgs

        public class NewMailInfo:EventArgs
        {
            private readonly string msg, from, to;
            public string Msg { get { return msg; } }
            public string From { get { return from; } }
            public string To { get { return to; } }
            public NewMailInfo(string _from, string _to, string _msg)
            {
                msg = _msg;
                to = _to;
                from = _from;
            }
        }

    2、邮件管理类:负责接收新邮件,并通知注册的其他类(如:传真机、打印机等)
    首先,定义一个处理新邮件方法,将相关信息赋予邮件信息承载类,并调用通知方法。

            public void SimulateNewMail(string from, string to, string msg)
            {
                NewMailInfo e = new NewMailInfo(from, to, msg);
                OnNewMail(e);
            }

    其次,新邮件通知功能,通知其他注册类。

            public event EventHandler<NewMailInfo>  NewMail;                
            protected virtual void OnNewMail(NewMailInfo e)
            {
                EventHandler<NewMailInfo> temp = System.Threading.Interlocked.CompareExchange(ref NewMail, null, null);
                if (temp != null)
                    temp(this, e);
            }

    当编译器遇检测到 event 关键字时,会将事件:

    public event EventHandler MsgEvent;

    翻译成三部分

    1、

    private EventHandler<NewMailInfo> _newmail = null;
    • 委托引用链,用于存储最终注册的方法引用。
    • 私有委托,private防止外类的修改。
    • 后面的add() 和 remove()方法,用于向这个委托引用链添加和删除引用。

    2、

     public void add_NewMail(EventHandler<NewMailInfo> value)
            {
                //当前委托链
                EventHandler<NewMailInfo> newmail = this._newmail;
                EventHandler<NewMailInfo> prevHandler;
                do
                {
                    prevHandler = newmail;
                    EventHandler<NewMailInfo> newHandler = (EventHandler<NewMailInfo>)Delegate.Combine(prevHandler, value);
                    newmail = System.Threading.Interlocked.CompareExchange(ref this._newmail, newHandler, prevHandler);
                } while (newmail != prevHandler);
            }
    • 编译器生成add_NewMail(EventHandler<NewMailInfo> value)方法
    • 将当前的委托链备份一份。EventHandler<NewMailInfo> newmail = this._newmail;

    • 循环体内,EventHandler<NewMailInfo> newHandler = (EventHandler<NewMailInfo>)Delegate.Combine(prevHandler, value);将当前需要注册的方法引用追加到委托链 prevHandler,并生成新的委托链  newHandler
    • newmail = System.Threading.Interlocked.CompareExchange(ref this._newmail, newHandler, prevHandler); 当前this._newmail,与prevHandler 引用实例是否一样。如果一样就将 newHandler的值赋值给this._newmail。

    3、类似add功能 的remove()方法。

    整个邮件管理类就可以这样实现了。

        public class MailManager
        {        
            public event EventHandler<NewMailInfo>  NewMail;                
            protected virtual void OnNewMail(NewMailInfo e)
            {
                EventHandler<NewMailInfo> temp = System.Threading.Interlocked.CompareExchange(ref NewMail, null, null);
                if (temp != null)
                    temp(this, e);
            }
            public void SimulateNewMail(string from, string to, string msg)
            {
                NewMailInfo e = new NewMailInfo(from, to, msg);
                OnNewMail(e);
            }
            
        }
    View Code


    3、其他类如何注册

       public class Fax
        {
            public Fax(MailManager mm)
            {
                mm.NewMail+=FaxMsg;
            }
            public void FaxMsg(object sender, NewMailInfo e)
            {
                
                Console.Write(e.Msg+"【来自传真机】");
            }
        }

    当前使用+=进行注册,其实也是也是用add()方法进行注册方法引用。

    三、总结

    • 编译器遇到event这个标志会进行翻译。一个私有的委托,向外开放注册add和注销remove方法。事件只能当前类进行修改,对外只提供注册和注销方法。
    • 拥有事件的类在触发事件就会调用这个委托所维护的新的方法列表对方法进行回调,理所当然的拥有了通知其他对象的能力。
    • 外部类通过注册事件,可以得到通知,并进行属于自己方式的处理。

     

  • 相关阅读:
    [APIO2012]派遣
    Luogu_2774 方格取数问题
    Luogu4149 [IOI2011]Race
    Luogu_4886 快递员
    Loj_6282. 数列分块入门 6
    LOJ 6281 数列分块入门 5
    三维偏序 cdq
    【逆序对】 模板
    【luogu P1637 三元上升子序列】 题解
    【luogu P3609 [USACO17JAN]Hoof, Paper, Scissor蹄子剪刀布】 题解
  • 原文地址:https://www.cnblogs.com/sunchong/p/sunchong.html
Copyright © 2011-2022 走看看