• C#事件


    如果定义一个事件,就意味着类型要提供以下能力

    1.方法可登记它对该事件的关注

    2.方法可注销它对该事件的关注

    3.该事件发生时,登记了的方法会收到通知

    类型之所以能提供事件通知的功能,是因为类型维护了一个已登记方法的列表,事件发生后,类型将通知列表中所有已登记的方法。

    CLR的事件是建立在委托的基础上,委托是调用回调方法的一种类型安全的方式,对象通过回调方法来接受它们订阅的通知。

    场景:电子邮件应用程序,当电子邮件到达时,用户希望将该邮件转发给传真机或寻呼机

    clipboard

    1.1、第一步:定义类型来容纳所有需要发送给事件通知接受者的附加信息

    事件引发时,引发事件的对象可能希望向接收事件通知的对象传递一些附加信息。好吧,我们这个类可以这样定义

    复制代码
    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; } }
    
        }
    复制代码

    EventArgs类:

    clipboard[1]

    1.2、第二步:定义事件成员

    事件成员使用C#关键字event来定义,每个事件成员都要指定以下内容:

    1.一个可访问性标识符(几乎肯定是public,因为要暴漏给其他订阅者)

    2.一个委托类型,它要指出要调用的方法的原型

    internal class MailManager{
    
        //第二步定义事件成员
        public event EventHandler<NewMailEventArgs> NewMail;
    
    }

    clipboard[2]

    .3、第三步:定义负责引发事件的方法来通知事件的登记对象

    类应定义一个受保护的虚方法。要引发事件时,当前类及其派生类中的代码会调用该方法。该方法要获取一个参数,也就是一个NewMailEventArgs对象(包括附加信息),该方法默认实现只检查是否有对象登记了对事件的关注,如果有就引发事件,通知登记者

    复制代码
    internal class MailManager
    
        {
    
            public event EventHandler<NewMailEventArgs> NewMail;
    
            protected virtual void OnNewMail(NewMailEventArgs e)
            {
                //出于线程安全考虑,现将对委托字段引用复制到一个临时字段中
                EventHandler<EventArgs> temp = System.Threading.Interlocked.CompareExchange(ref NewMail, null, null);
    
                //任何方法登记了对事件的关注,就通知他们
                if (temp!=null)
                {
                    temp(this, e);
                }
            }
        }
    复制代码

    clipboard[3]

    为了方便起见,可以定义一个扩展方法来封装这个线程安全逻辑

    复制代码
    public static class EventArgExtensions{
        public static void Raise<TEventArgs>(this TEventArgs e,Object sender,ref EventHandler<TEventArgs> eventDelegate)
        where TEventArgs:EventArgs{
            //出于线程安全考虑,现将对委托字段引用复制到一个临时字段中
            EventHandler<EventArgs> temp = System.Threading.Interlocked.CompareExchange(ref NewMail, null, null);
            //任何方法登记了对事件的关注,就通知他们
          if (temp!=null)
            {
                temp(this, e);
            }
        }
    }
    复制代码

    现在,可以像下面这样重写OnNewMail方法:

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

    1.4、第四步:定义方法将输入转化为期望事件

    现在还需要一些方法来获取输入,并把它转化为事件的引发,在MailManager的例子中是调用SimulateNewMail方法来指出一封新的电子邮件已到达MailManager:

    复制代码
    internal class MailManager{
    
        //第四步:定义方法将输入转化为期望事件
    
        public void SimulateNewManager(string from ,string to,string subject){
            //构造一个对象来容纳想传给通知接受者的信息
            NewMailEventArgs e=new NewMailEventArgs(from,to,subject);
            //调用虚方法通知对象事件已发生
            //如果没有类型重写该方法,我们的对象将通知事件的所有登记对象
            OnNewMail(e);
        }
    }
    复制代码

    clipboard[4]

    1.5、第五步:设计订阅者,及回调方法

    复制代码
    internal sealed class Fax{
        //MailManager传给构造器
       public Fax(MailManager mm)
        {
            //构造EventHandler<NewMailEventArgs>委托的一个实例
            //使他引用我们的FaxMsg回调方法
            //向MailManager的NewMail事件登记我们的回调方法
            mm.NewMail+= FaxMsg;
        }
        //回调方法,新电子邮件到达,MailManager将回调此方法
        //'sender'表示MailManager对象,便于将信息回传给它
        //'e'表示MailManager对象想传递给我们的附加事件信息
        private void FaxMsg(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 mm)
        {
            //向MailManager的NewMail事件注销自己对这个事件的关注
            mm.NewMail-=FaxMsg;
        }
    }
    复制代码

    1.6、程序入口:

    复制代码
    class Program
        {
            static void Main(string[] args)
            {
                //初始化邮件管理
                MailManager mm = new MailManager();
                //Fax订阅邮件
                Fax f = new Fax(mm);
                //Pager订阅邮件
                Pager p = new Pager(mm);
                //新邮件到达,通知订阅者,调用它们的回调函数
                mm.SimulateNewManager("boss", "all", "meetting");
            }
        }
    复制代码

    clipboard[5]

  • 相关阅读:
    基于udp简单聊天的系统
    网络编程_tcp与dup协议简单应用
    logging_modules
    linux内核配置与编译
    linux内核简介
    对于国嵌上学期《一跃进入C大门》Mini2440的代码修正
    通过按键玩中断
    MMU功能解析、深入剖析、配置与使用
    C与汇编混合编程
    一跃进入C大门
  • 原文地址:https://www.cnblogs.com/hailiang2013/p/2846413.html
Copyright © 2020-2023  润新知