1. C#事件的概念

C# 中时间允许一个对象将发生的事件通知其他对象,将发生的事件的事件源叫发行者,通知其他的对象叫订阅者,但是订阅者可以定义也可以不定义(事件发生者也可以是事件的订阅者)

 1 class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             var user = new User();
 6             user.Name = "xiaohon";
 7             user.Password = "123";
 8
 9             user.EventLogin += new User.DelegateLogin(User_EventLogin);
10             user.Login();
11
12         }
13
14         private static void User_EventLogin()
15         {
16             Console.WriteLine("login seccessful");
17         }
18     }
19
20     class User
21     {
22         public delegate void DelegateLogin();   //  定义一个委托
23         public event DelegateLogin EventLogin;  //  定义一个事件(事件用关键字加委托名来定的且后面无括号)
24
25         public string Name { get; set; }
26         public string Password { get; set; }
27
28         /// <summary>
29         /// 类的方法(可做为方法的参数即委托)
30         /// </summary>
31         public void Login()
32         {
33             Console.WriteLine("Login.....");
34
35             //  引发事件
36             if (EventLogin != null)
37             {
38                 EventLogin();
39             }
40         }
41     }

View Code

2. 事件的声明

。事件是成员,它必须声明在类或类型中,和其他成员一样。

。由于事件不是类型,我们不能像委托那样使用对象创建表达式(new 表达式)来创建它的对象。

。事件成员被隐式自动初始化为 null 。

3. 委托类型和 EventHandler

。事件声明需要委托类型的名字,我们可以声明一个委托类型或使用已存在的。声明一个委托类型,它必须指定事件保存的方法的签名和返回类型。

。更好的方案就是使用 EventHandler 委托。

4. 触发事件

。在触发事件之前和 null 进行比较,从而查看是否包含任何事件处理程序,如果事件是 null ,则表示没有。

。出发事件本身看起来像调用函数一样。

5. 订阅事件

。使用 += 运算符来添加事件处理程序(即绑定多个方法),方法可以是:

  。实例方法

  。静态方法

  。匿名方法

  。Lambda 表达式

。使用 -= 运算符来移除事件处理程序(即删除多个方法)

6. 关于 EventArg 类

。EventArgs 被设计为不能专递任何数据。它用于不需要传递数据的事件处理程序。

。通过扩展 EventArgs 来传递数据。

7. 观察者(Observer)设计模式的一种实现

热水器,加电烧水,当水温超过 95 度的时候:
  1. 扬声器会开始 发出语音,告诉你水的温度;
  2. 液晶屏也会改变水温的显示,来提示水已经快烧开了。
如何在水快烧开的时候通知报警器和显示器?

1. 警报器和显示器告诉热水器,它对它的温度比较感兴趣(注册)。
2. 热水器知道后保留对警报器和显示器的引用。
3. 热水器进行烧水这一动作,当水温超过 95 度时,通过对警报器和显示器的引用,自动 调用警报器的 MakeAlert()方法、显示器的 ShowMsg()方法

。Observer 设计模式:Observer 设计 模式是为了定义对象间的一种一对多的依赖关系,以便于当一个对象的状态改变时,其他依赖 于它的对象会被自动告知并更新。Observer 模式是一种松耦合的设计模式
。Observer 设计模式中主要包括如下两类对象:
  。Subject:监视对象,它往往包含着其他对象所感兴趣的内容。在本范例中,热水器就是一个监视对象,它包含的其他对象所感兴趣的内容,就是 temperature 属性,当这个属性的值快到 100 时,会不断把数据发给监视它的对象。
  。Observer:观察者,它监视 Subject,当 Subject 中的某件事发生的时候,会告知 Observer,而 Observer 则会采取相应的行动。在本范例中,Observer 有警报器和显示器,它们采取的行动分别是发出警报和显示水温。

常规的实现:

 1  class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             var heater = new Heater();  //  创建热水器对象
 6             var alarm = new Alarm();    //  创建报警器对象
 7
 8             heater.BoilEvent += alarm.MakeAlarm;    //  注册报警方法
 9             heater.BoilEvent += (new Alarm()).MakeAlarm;    //  给匿名对象注册方法
10             heater.BoilEvent += Display.ShowMsg;    //  注册静态方法
11
12             heater.BoilWater();     //  开始烧水,根据方法的条件会自动调用注册的方法
13
14             Console.ReadKey();
15         }
16     }
17
18     /// <summary>
19     /// 热水器
20     /// </summary>
21     class Heater
22     {
23         private int temperature;    //  温度
24         public delegate void BoilHandler(int temp);     //  声明委托
25         public event BoilHandler BoilEvent;     //  声明事件
26
27         /// <summary>
28         /// 烧水
29         /// </summary>
30         public void BoilWater()
31         {
32             for(int i = 95; i <= 100; i++)
33             {
34                 temperature = i;
35                 if (temperature > 95)
36                 {
37                     //  如果定义的事件有对象注册
38                     if(BoilEvent != null)
39                     {
40                         //  则执行其中的所有方法
41                         BoilEvent(temperature);
42                     }
43                 }
44             }
45         }
46     }
47
48     /// <summary>
49     /// 温度显示器
50     /// </summary>
51     class Display
52     {
53         /// <summary>
54         /// 显示方法
55         /// </summary>
56         /// <param name="temp">温度</param>
57         public static void ShowMsg(int temp)
58         {
59             Console.WriteLine("显示器:水快烧开了,当前温度是{0}度", temp);
60         }
61     }
62
63     /// <summary>
64     /// 报警器
65     /// </summary>
66     class Alarm
67     {
68         /// <summary>
69         /// 报警方式
70         /// </summary>
71         /// <param name="temp">温度</param>
72         public void MakeAlarm(int temp)
73         {
74             Console.WriteLine("当前温度是" + temp + "度");
75         }
76     }

常规的实现

8. .Net Framework 中的委托和事件

1. 委托类型的名称都应该以 EventHandler 结束。

2. 委托的原型定义:有一个 void 返回值,并接受两个输入参数:一个 Object 类型,一个 EventArgs 类型(或继承自 EventArgs)。

3. 事件的命名为委托去掉 EventHandler 之后剩余的部分。

4. 继承自 EventArgs 的类型应该以 EventArgs 结尾。

5. 委托声明原型中的 Object 类型的参数代表了 Subject ,也就是监视对象,在本例中是 Heater(热水器)。回调函数(比如 Alarm 的MakeAlert)可以通过它访问触发事件的对象(Heater)。

6. EventArgs 对象包含了 Observer 所感兴趣的数据,在本例中是 temperature。

改进后的代码:

  1  class Program
  2     {
  3         static void Main(string[] args)
  4         {
  5             var heater = new Heater();  //  创建热水器对象
  6             var alarm = new Alarm();    //  创建报警器对象
  7
  8             //heater.BoilEvent += alarm.MakeAlarm;    //  注册报警方法
  9             //heater.BoilEvent += (new Alarm()).MakeAlarm;    //  给匿名对象注册方法
 10
 11             heater.Boiled += Display.ShowMsg;    //  注册静态方法
 12             heater.Boiled += new Heater.BoilEventHandler(alarm.MakeAlarm);  //  另一种注册方式
 13
 14             heater.BoilWater();     //  开始烧水,根据方法的条件会自动调用注册的方法
 15
 16             Console.ReadKey();
 17         }
 18     }
 19
 20     /// <summary>
 21     /// 热水器
 22     /// </summary>
 23     class Heater
 24     {
 25         private int _Temperature;    //  温度
 26         public string Brand = "格星 X-1219";
 27         public string Manufacturer = "xx 格星电器有限责任公司";
 28
 29         //  委托的原型定义:有一个 void 返回值,并接受两个输入参数:一个 Object 类型, 一个 EventArgs 类型(或继承自 EventArgs)
 30         public delegate void BoilEventHandler(object sender,BoiledEventArgs e);     //  声明委托   委托类型的名称都应该以 EventHandler 结束
 31         public event BoilEventHandler Boiled;     //  声明事件  事件的命名为委托去掉 EventHandler 之后剩余的部分
 32
 33         /// <summary>
 34         /// 构建一个可以重写的方法,以便它的派生类拒绝其他对象的访问
 35         /// </summary>
 36         /// <param name="e">事件参数</param>
 37         protected virtual void OnBoiled(BoiledEventArgs e)
 38         {
 39             if(Boiled != null)
 40             {
 41                 Boiled(this, e);
 42             }
 43         }
 44
 45         /// <summary>
 46         /// 烧水
 47         /// </summary>
 48         public void BoilWater()
 49         {
 50             for(int i = 95; i <= 100; i++)
 51             {
 52                 _Temperature = i;
 53                 if (_Temperature > 95)
 54                 {
 55                     BoiledEventArgs e = new BoiledEventArgs(_Temperature);
 56                     OnBoiled(e);
 57                 }
 58             }
 59         }
 60     }
 61
 62     /// <summary>
 63     /// 定义一个事件参数类,用于承载需要传递给 Observer 所感兴趣的信息
 64     /// 继承自 EventArgs 的类型应该以 EventArgs 结尾
 65     ///  EventArgs 对象包含了 Observer 所感兴趣的数据,在本例中是 _Temperature
 66     /// </summary>
 67     public class BoiledEventArgs : EventArgs
 68     {
 69         public readonly int _Temperature;
 70
 71         public BoiledEventArgs(int temp)
 72         {
 73             this._Temperature = temp;
 74         }
 75     }
 76
 77     /// <summary>
 78     /// 温度显示器
 79     /// </summary>
 80     class Display
 81     {
 82         /// <summary>
 83         /// 显示方法
 84         /// </summary>
 85         /// <param name="temp">温度</param>
 86         public static void ShowMsg(object sender,BoiledEventArgs e)
 87         {
 88             var obj = sender as Heater;
 89             Console.WriteLine("显示器{0}({1})", obj.Brand, obj.Manufacturer);
 90             Console.WriteLine("显示器:水快烧开了,当前温度是{0}度", e._Temperature);
 91         }
 92     }
 93
 94     /// <summary>
 95     /// 报警器
 96     /// </summary>
 97     class Alarm
 98     {
 99         /// <summary>
100         /// 报警方式
101         /// </summary>
102         /// <param name="temp">温度</param>
103         public void MakeAlarm(object sender,BoiledEventArgs e)
104         {
105             Console.WriteLine("当前温度是" + e._Temperature + "度");
106         }
107     }

改进后的代码

参考网址:https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/events/

转载于:https://www.cnblogs.com/huangzewei/p/7300080.html

part01.04 事件相关推荐

  1. 【青少年编程】【Scratch】04 事件模块

    「青少年编程竞赛交流群」已成立(适合6至18周岁的青少年),公众号后台回复[Scratch]或[Python],即可进入.如果加入了之前的社群不需要重复加入. 微信后台回复"资料下载&quo ...

  2. 04 | 事件调度层:为什么 EventLoop 是 Netty 的精髓?

    1.单线程模型 略- 2.多线程模型 略- 3.主从多线程模型 略- 4.Netty EventLoop 实现原理 4.1.EventLoop 是什么 每当事件发生时,应用程序都会将产生的事件放入事件 ...

  3. vue-06 监听事件-自学视频

    01 可以用 v-on 指令监听 DOM 事件,并在触发时运行一些 JavaScript 代码. <div id="app"><button v-on:click ...

  4. 【传智播客】Libevent学习笔记(四):事件event

    目录 00. 目录 01. 事件概述 02. 创建事件 03. 事件的标志 04. 事件持久性 05. 超时事件 06. 信号事件 07. 设置不使用堆分配的事件 08. 事件的未决和非未决 09. ...

  5. 如何基于IT事件全生命管理周期,提升业务连续性?

    进入数字化时代,IT架构面临的复杂性越来越高,业务连续性管理这项IT最基本的工作,也成为了很多行业或企业IT运维的最核心任务:业务连续性管理是一个持续不断提升的过程,围绕"快速发现事件→快速 ...

  6. 【青少年编程(第24周)】Python-Turtle组队学习结营!

    2021年08月01日(周日)晚20:00我们在青少年编程竞赛交流群开展了第二十四次直播活动.我们直播活动的主要内容如下: 首先,我们奖励了上周测试超过60分的小朋友. 其次,讲解了上次测试中小朋友们 ...

  7. 【青少年编程】黄羽恒:漫天飞雪

    「青少年编程竞赛交流群」已成立(适合6至18周岁的青少年),公众号后台回复[Scratch]或[Python],即可进入.如果加入了之前的社群不需要重复加入. 微信后台回复"资料下载&quo ...

  8. 【青少年编程】黄羽恒:Python

    「青少年编程竞赛交流群」已成立(适合6至18周岁的青少年),公众号后台回复[Scratch]或[Python],即可进入.如果加入了之前的社群不需要重复加入. 微信后台回复"资料下载&quo ...

  9. 【青少年编程】黄羽恒:平行空间

    「青少年编程竞赛交流群」已成立(适合6至18周岁的青少年),公众号后台回复[Scratch]或[Python],即可进入.如果加入了之前的社群不需要重复加入. 微信后台回复"资料下载&quo ...

最新文章

  1. 《C和C++代码精粹》——2.5 普通指针
  2. python报错UnicodeDecodeError: ‘gbk‘ codec can‘t decode解决方案
  3. Ant build.xml中的各种变量
  4. 关于编译器的一个疑问
  5. SAP Spartacus开启SSR服务器端渲染之后,和默认客户端渲染的差异比较
  6. 搜索重复代码_LeetCode专题——详解搜索算法中的搜索策略和剪枝
  7. python涉及到的逻辑_涉及逻辑运算的python表达式的运算顺序
  8. C++设计模式-Composite组合模式
  9. vue-cli3项目运行时一直发http://localhost:8080/sockjs-node/info?t=1462183700002请求
  10. android小小的开发细节
  11. ubuntu系统20.04 无线网卡QCA6174 wifi不存在或找不到解决方法 红米笔记本
  12. 苹果计算机重装系统步骤,苹果mac系统重装_苹果电脑Mac系统重装方法
  13. 计算机情绪识别属于什么方向,情绪识别
  14. Java编程笔记2:初始化和清理
  15. 李峋的爱心表白代码来了
  16. 各种浏览器的内核是什么
  17. 2017 iOS最新面试题汇总(二)
  18. JavaScript-05
  19. 银河麒麟操作系统如何开启kdump
  20. 刷脸支付赋予日常场景更多的功能和应用

热门文章

  1. mysql 4.0手工注入_手工注入——MySQL手工注入实战和分析
  2. python优雅编程_Python优雅编程——Collections模块中的高性能数据类型
  3. birt脚本for循环语句_如何使用 for 循环语句嵌套方法!
  4. Android逆向笔记-查看app的log打印(含调试方式打开)
  5. Android逆向笔记-某水果大作战内购破解思路
  6. Java工作笔记-webService发布时通用的4个注解
  7. MySQL笔记-mysql权限授权及创建用户
  8. Qt文档阅读笔记-QThreadPool的解释及使用
  9. Linux学习笔记-Makefile的基本使用
  10. java redis hession_spring: 整合 springmvc shiro redis hessian rocketMQ