• 谈一谈C#的事件


    谈一谈C#的事件

    C#中事件基于委托,要理解事件要先理解委托,如果觉得自己关于委托不是很了解可以看看我前面写委托的文章

    事件基于委托,是一种功能受限的委托,为委托提供了一种发布/订阅机制

    使用委托时,一般会出现两种角色:广播者(发布者)和订阅者,这是一个非常常见的模型

    依然是用一个非常典型的例子来说明事件,举一个具体的例子就是微信公众号,广播者就是公众号管理员,订阅者就是普通用户。

    using System;
    
    class Program
    {
        static void Main(string[] args)
        {
            公众号 actionNet = new 公众号();
            用户 m = new 用户();
            
            // 订阅事件
            actionNet.Published += m.ReceiveMessage;
    
            // 执行动作,动作中包含广播行为
            actionNet.Publish();
        }
    }
    
    // 定义“发布”委托
    public delegate void PublishHandler();
    
    // 特别提醒:为了便于理解,我使用了中文类名,在真实项目中,请勿使用中文关键字
    class 公众号
    {
        public event PublishHandler Published;
    
        public void Publish()
        {
            Console.WriteLine("我是ActionNet,我发布了一条消息");
    
            // 使用了null判断运算符,如果Published为空则不执行后面相关调用
            // Published.Invoke()与Published()相同,都是执行委托/事件,后者是前者的简写
            // 这条语句就是广播行为
            Published?.Invoke();
        }
    }
    
    class 用户
    {
        public void ReceiveMessage()
        {
            Console.WriteLine("有一条新的公众号消息到达,请查阅!!!");
        }
    }
    

    首先广播者,这里的广播者是公众号类,首先定义了一个事件,然后定义了一个方法,在这个方法中触发事件,广播给所有订阅者

    订阅者是用户类,只有一个方法

    回到Main函数,首先实例化了一个公众号对象和用户对象

    然后使用+=将订阅者的方法注册到事件中(事件只能使用+=和-=注册和撤销订阅,后面会讲)

    最后是广播者调用了触发事件的方法,向所有订阅者广播(由事件委托执行订阅者注册到事件中的方法)

    标准事件模式

    .Net Framwork为事件编程定义了一个标准模式,目的是保持框架和用户代码的一致性,核心是System.EventArgs类,但是在.Net Core中并不再要求System.EventArgs类,这个下一节讲

    在.Net Framework的标准事件模式中,需要

    • 一个类,继承自EventArgs,类名根据包含的信息来命名,以EventArgs结尾

    • 事件所需的委托(框架定义了名为EventHandler<T>的泛型委托,满足下面的要求,且可以接受所有类型)

      • 委托必须以void作为返回值
      • 委托必须接受两个参数,第一个参数是object类型,第二个参数则是EventArgs的子类。第一个参数表明了事件的广播者,第二个参数则包含了需要传递的额外信息
      • 委托的名称必须以EventHandler结尾
    • 一个protected的虚方法来触发事件,方法名必须和事件名称一致,以On为前缀,并接受唯一的EventArgs参数

    下面我们来看前面的例子改写成标准模式的样子

    // 带参数的标准模式
    using System;
    
    class Program
    {
        static void Main(string[] args)
        {
            公众号 actionNet = new 公众号();
            用户 m = new 用户();
            
            // 订阅事件
            actionNet.Published += m.ReceiveMessage;
    
    
            // 执行动作,动作中包含广播行为
            actionNet.Publish("人生若只如初见");
        }
    }
    
    // 定义需要传递的额外信息类
    class MessageEventArgs : EventArgs
    {
        public MessageEventArgs(string message)
        {
            Message = message;
        }
        public string Message { get; set; }
    }
    
    // 定义事件的委托,这个委托.Net Framework定义好了的,其实不必再定义,在后面迁移到.Net Core时也改动更少
    // public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e) where TEventArgs : EventArgs;
    
    // 特别提醒:为了便于理解,我使用了中文类名,在真实项目中,请勿使用中文关键字
    class 公众号
    {
        public event EventHandler<MessageEventArgs> Published;
    
        protected virtual void OnPublished(MessageEventArgs e)
        {
            Console.WriteLine("我是ActionNet,我发布了一条消息");
    
            // this表明事件的广播者是这个类,e是需要传递的额外信息
            Published?.Invoke(this,e);
        }
    
        public void Publish(string content)
        {
            OnPublished(new MessageEventArgs(content));
        }
    }
    
        
    
    class 用户
    {
        public void ReceiveMessage(object sender,MessageEventArgs e)
        {
            Console.WriteLine("有一条新的公众号消息到达,请查阅!!!");
            Console.WriteLine($"消息来自:{sender}");
            Console.WriteLine(e.Message);
        }
    }
    
    // 不需要额外信息的标准模式
    using System;
    
    class Program
    {
        static void Main(string[] args)
        {
            公众号 actionNet = new 公众号();
            用户 m = new 用户();
            
            // 订阅事件
            actionNet.Published += m.ReceiveMessage;
    
    
            // 执行动作,动作中包含广播行为
            actionNet.Publish("人生若只如初见");
        }
    }
    
    // 不需要用以传递信息的额外信息类
    
    
    // 定义事件的委托,这个委托.Net Framework定义好了的,其实不必再定义,在后面迁移到.Net Core时也改动更少
    // public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e) where TEventArgs : EventArgs;
    
    // 特别提醒:为了便于理解,我使用了中文类名,在真实项目中,请勿使用中文关键字
    class 公众号
    {
        // 使用非泛型的EventHandler委托类型
        public event EventHandler Published;
    
        // 触发事件的方法,直接接收EventArgs类型参数
        protected virtual void OnPublished(EventArgs e)
        {
            Console.WriteLine("我是ActionNet,我发布了一条消息");
    
            // this表明事件的广播者是这个类,e是需要传递的额外信息
            Published?.Invoke(this,e);
        }
    
        public void Publish(string content)
        {
            //无需额外的信息,则无需创建EventArgs实例,直接返回空
            OnPublished(EventArgs.Empty);
        }
    }
    
        
    
    class 用户
    {
        public void ReceiveMessage(object sender,EventArgs e)
        {
            Console.WriteLine("有一条新的公众号消息到达,请查阅!!!");
            Console.WriteLine($"消息来自:{sender}");
        }
    }
    

    .Net Core的标准事件模式

    .NET Core 的标准事件模式较为宽松。 在此版本中,EventHandler<TEventArgs> 定义不再要求 TEventArgs 必须是派生自 System.EventArgs 的类

    这个可以看一下官方文档,后面有机会我再更新

    事件相对于委托的限制

    事件是一种功能受限的委托,具体受限的地方是事件只能使用+=-=,相比于委托少了=(这是其中之一,还理解得不是很透彻,后面再补)

    拿前面的代码actionNet.Published += m.ReceiveMessage;这一句是添加订阅,如果不需要了可以使用-=删除订阅,但是不能使用actionNet.Published = null,这样的代码更加健壮

  • 相关阅读:
    前端基础进阶变量对象详解
    伪元素::before与::after的用法
    网站性能优化你需知道的东西
    Python爬虫音频数据
    python一步高级编程
    Android APK打包流程
    软件漏洞学习
    pycrypto 安装
    ubuntu16.04中将python3设置为默认
    Android NDK 编译选项设置[zhuan]
  • 原文地址:https://www.cnblogs.com/wujuncheng/p/13428118.html
Copyright © 2020-2023  润新知