zoukankan      html  css  js  c++  java
  • 读<<CLR via C#>>总结(11) 详谈事件

      什么是事件?
        事件是类的一种成员。如果类型定义了事件,那么它就可以通知其它对象发生了特定的事情(比如Button的Click事件)。事件是实现这种交互的类型成员。
        事件是建立在委托的基础之上,事件是被封装的委托。

    一,发布者和订阅者模式

      理解这幅图对于理解事件的原理非常重要:


      1,发布者类订义了事件成员。
      2,订阅者类注册在事件成员被触发时要调用的方法(事件处理程序)。
      3,当发布者触发事件时,所有列表中的事件处理程序都会被调用。  

    二,实际案例

      这是一个电子邮件到达通知的例子,当电子邮件到达时,会引发NewMail事件,而注册到这个事件上的Fax和Pager都会收到通知,并以自己的方式处理该邮件。
      代码如下:

    namespace EventDemo2
    {
        class Program
        {
            static void Main(string[] args)
            {
                MailManager mm = new MailManager();
                Fax fax = new Fax(mm);
                Pager pager = new Pager(mm);
                mm.SimulateNewMail("A","B","Hi,how are you?");
    
                Console.WriteLine();
                Console.WriteLine("********Pager undo register********");
                pager.Unregister(mm);
                mm.SimulateNewMail("B", "A", "I'm fine,and you?");
                Console.ReadKey();
            }
        }
    
        //发布者类
        internal class MailManager
        { 
            //1,声明事件
            public event EventHandler<NewMailEventArgs> NewMail;
    
            //2,触发事件1-引发事件的方法
            protected virtual void OnNewMail(NewMailEventArgs e)
            {
                if (NewMail != null)
                {
                    NewMail(this,e);
                }
            }
    
            //3,触发事件2-将输入转化为期望事件
            public void SimulateNewMail(string from, string to, string subject)
            {
                NewMailEventArgs e = new NewMailEventArgs(from,to,subject);
                OnNewMail(e);
            }
        }
    
        //自定义类,通过扩展EventArgs来传递数据
        //这里容纳发送给事件接受者的信息
        internal class NewMailEventArgs : EventArgs
        {
            private readonly string _from, _to, _subject;
    
            public NewMailEventArgs(string from,string to,string subject)
            {
                _from = from;
                _to = to;
                _subject = subject;
            }
    
            public string From
            {
                get { return _from; }
            }
            public string To
            {
                get { return _to; }
            }
            public string Subject
            {
                get { return _subject; }
            }
        }
    
        //订阅者类1
        internal class Fax
        {
            public Fax(MailManager mm)
            {
                mm.NewMail += new EventHandler<NewMailEventArgs>(FaxMsg);//注册事件处理程序
                //mm.NewMail += FaxMsg;//与上面等价
            }
    
            public void Unregister(MailManager mm)
            {
                mm.NewMail -= new EventHandler<NewMailEventArgs>(FaxMsg);//取消事件处理程序
            }
    
            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);
            }
        }
        
        //订阅者类2
        internal class Pager
        {
            public Pager(MailManager mm)
            {
                mm.NewMail +=PagerMsg;//注册事件处理程序
            }
    
            public void Unregister(MailManager mm)
            {
                mm.NewMail -= PagerMsg;//取消事件处理程序
            }
    
            private void PagerMsg(object sender, NewMailEventArgs e)
            {
                Console.WriteLine("Pager mail message:");
                Console.WriteLine("From:{0}, To={1}, Subject={2}", e.From, e.To, e.Subject);
            }
        }
    }

    程序输出结果如下图所示。

    注意事项:1,+=和-=是事件中唯一允许使用的运算符,分别代表注册事件处理程序和取消注册事件处理程序。
         2,不要误认为事件是类型,事件是类型的一种成员,所以它也不可以使用对象创建表达式(new表达式)来创建它的对象。
         3,调用事件与调用委托相似(与调用方法也相似),但是要注意它的参数必须要与事件的委托匹配。
         4,订阅事件(注册事件处理程序)有多种方法,可以是实例方法,静态方法,匿名方法,或lambda表达式。最常见的是使用委托形式的实例方法。如:
           btn.Click+=new EventHandler(btn_Click);//等价于:btn.Click+=btn_Click;
         5,EventHandler委托的第二个参数EventArgs默认是不能传递任何数据的,如果希望被设计成能传递数据,必须自定义一个从EventArgs继承的类,并使用私有字段来保存需要被传递的数据。

  • 相关阅读:
    内存
    jmeter设置全局变量
    tomcat(1)
    JVM(一)
    内存溢出
    消息中间件
    上下文切换(二)
    平均负载(二)
    requests模块
    Pycharm如何配置Git
  • 原文地址:https://www.cnblogs.com/mcgrady/p/2570207.html
Copyright © 2011-2022 走看看