C# 知识回顾-Event事件

昨天,通过《C# 知识回顾 - 事件入门》介绍了事件的定义及简单用法,今天我们通过控制台来看下“发布 - 订阅”的基本用法。

一、发布基于 .NET 类库的事件

.NET类库中的所有事件均基于 EventHandler 委托,定义如下:

public delegate void EventHandler(object sender, EventArgs e);你可以尝试手动输入 EventHandler ,然后按下“F12”跳转到定义:

.NET 2.0 引入了该委托的一个泛型版本,即 EventHandler<TEventArgs>。【备注】虽然我们定义的事件可以基于任何自定的委托类型,但建议使用内置的 EventHandler 进行扩展。

二、采用 EventHandler 模式发布事件1.这里选择继承了 BCL 中的类 EventArgs,可以在事件的触发时进行数据的传递。
1     class MyEventArgs : EventArgs
2     {
3         public string Message { get; private set; }
4
5         public MyEventArgs(string message)
6         {
7             Message = message;
8         }
9     }
2.这里的第二个参数就是自定义的 MyEventArgs 类型,它继承了 EventArgs。 
delegate void MyEventHandler(object sender, MyEventArgs args);

3.声明事件的几种形式:

(1)如果没有自定义 EventArgs 类,你可以直接使用 C# 中默认提供的非泛型 EventHandler 委托。
public event EventHandler MyEvent;

(2)如果使用的是非泛型的 EventHandler,并且写了一个自定义由 EventArgs 派生的类,可修改如下

public event MyEventHandler MyEvent;

(3)如果使用的是高级的泛型版本,就不需要自定义委托。你只需要简单地将事件类型指定
为 EventHandler<MyEventArgs>,将尖括号中的内容替换为自己的类的名称。 

三、一个简单的发布订阅 Demo
 下面的示例通过将自定义的 MyEventArgs 类和 EventHandler<TEventArgs> 进行演示:
This is MyEventArgs.cs  //事件参数
 /// <summary>
 2     /// 事件参数
 3     /// </summary>
 4     /// <remarks>一个自定义的类:自定义事件的参数</remarks>
 5     class MyEventArgs : EventArgs
 6     {
 7         public string Message { get; }
 8
 9         public MyEventArgs(string message)
10         {
11             Message = message;
12         }
13     }
This is Publisher.cs  //发布者
 1     /// <summary>
 2     /// 事件发布者
 3     /// </summary>
 4     class Publisher
 5     {
 6         //声明一个泛型事件
 7         public event EventHandler<MyEventArgs> MyEvent;
 8
 9         public void Publish()
10         {
11             Console.WriteLine("Publis is starting");
12
13             //你可以在事件触发前写些代码
14
15             OnMyEvent(new MyEventArgs(DateTime.Now.ToString()));
16         }
17
18         /// <summary>
19         /// 触发事件
20         /// </summary>
21         /// <param name="args"></param>
22         /// <remarks>虚方法,允许子类重写调用行为</remarks>
23         protected virtual void OnMyEvent(MyEventArgs args)
24         {
25             //只有在事件订阅时(!= null),才触发事件
26             MyEvent?.Invoke(this, args);
27         }
28     }
This is Subscriber.cs  //订阅者
 1     /// <summary>
 2     /// 订阅者
 3     /// </summary>
 4     class Subscriber
 5     {
 6         public Guid Guid { get; }
 7
 8         public Subscriber(Publisher publisher)
 9         {
10             Guid = Guid.NewGuid();
11             //使用 C# 2 的语法进行订阅
12             publisher.MyEvent += Publisher_MyEvent;
13         }
14
15         /// <summary>
16         /// 事件处理程序
17         /// </summary>
18         /// <param name="sender"></param>
19         /// <param name="args"></param>
20         private void Publisher_MyEvent(object sender, MyEventArgs args)
21         {
22             Console.WriteLine($"    Message is {args.Message}, Guid is {Guid}.");
23         }
24     }
This is Program.cs   //控制台,用于启动
 class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             var publisher = new Publisher();
 6             var subscriber1 = new Subscriber(publisher);
 7             var subscriber2 = new Subscriber(publisher);
 8
 9             //触发事件
10             publisher.Publish();
11
12             Console.WriteLine("OK!");
13             Console.Read();
14         }
15     }  

四、实现自定义事件访问器

事件一种是特殊类型的多播委托,只能从声明它的类中进行调用。这些方法需要预先通过事件访问器添加到委托的调用列表中,事件访问器跟我们平时使用的属性访问器,特殊的是他们的名字,事件访问器被命名为 add 和 remove。如果在代码中没有提供自定义的事件访问器,编译器会自动添加事件访问器。但在某些情况下,您可能需要提供自定义的行为。
 class MyClass
 2     {
 3         /// <summary>
 4         /// 锁
 5         /// </summary>
 6         private static object Locker = new object();
 7
 8         /// <summary>
 9         /// 接口
10         /// </summary>
11         public interface IMyEvent
12         {
13             event EventHandler OnCall;
14         }
15
16         public class MyEvent : IMyEvent
17         {
18             /// <summary>
19             /// 触发前事件
20             /// </summary>
21             event EventHandler PreEvent;
22
23             public event EventHandler OnCall
24             {
25                 add
26                 {
27                     lock (Locker)
28                     {
29                         PreEvent += value;
30                     }
31                 }
32                 remove
33                 {
34                     lock (Locker)
35                     {
36                         PreEvent += value;
37                     }
38                 }
39             }
40         }
41     }
				
时间: 2024-10-28 15:10:37

C# 知识回顾-Event事件的相关文章

概率与统计 知识回顾(一) 事件的概率

一.概率是什么 概率是表示某种情况(事件)出现的可能性大小的一种数量指标,它介于0与1之间. 1.1 主观概率 凭着经验和知识对事件发生的可能性作出的一种主观估计,主观概率可以理解为一种心态或倾向性. 1.2 等可能试验 假定某个试验有有限个可能的结果$e_1,e_2,\dots,e_N$.假定从该试验的条件及实施方法去分析,我们找不到任何理由认为其中某一结果,例如$e_i$,比任一其他结果,例如$e_j$,更具有优势(即更倾向于易发生),则我们只好认为,所有结果$e_1,e_2,\dots,e

[C#] C# 知识回顾 - Excetion 异常的介绍、使用和处理

Excetion 异常的介绍.使用和处理 目录 异常介绍 异常的特点 怎样使用异常 处理异常的 try-catch-finally 捕获异常的 Catch 块 释放资源的 Finally 块 一.异常介绍 我们平时在写程序时,无意中(或技术不够),而导致程序运行时出现意外(或异常),对于这个问题, C# 有专门的异常处理程序. 异常处理所涉及到的关键字有 try.catch 和 finally 等,用来处理失败的情况. CLR..NET 自身的类库.其它第三方库或者你写的程序代码都有可能会出现异

[C#] C# 知识回顾 - 异常介绍

异常介绍 C# 语言的异常处理功能可以帮助你在处理程序运行时出现的意外或异常情况. 异常处理使用 try.catch 和 finally 等关键字尝试执行某些操作,以处理失败情况,当然,尽管这些操作也有可能失败,如果你确定需要这样做,且希望在事后清理资源,就可以尝试这样做. 公共语言运行时 (CLR)..NET 或任何第三方库或者应用程序代码都有可能会生成异常. 异常是你可以使用 throw 关键字显式进行创建. 很多情况下,异常很可能不是由代码直接调用的方法引发,而是由调用堆栈中位置更靠下的另

C#知识回顾

Main函数是什么? a) 程序入口函数 在程序中使用Main函数有什么需要注意的地方? a) Main函数不能变,有且只有一个 CLR是什么? a) 公共语言运行时 b)  Common Language RunTime 程序集是什么? a) 编译后代码的集合.(包括exe和dll). 加载项目里所有的类到内存,并找到其中的主函数,并作为默认的启动函数调用执行. 当运行一个程序集的时候,CLR做了什么事情? a) 加载项目所有的类到内存,并找到其中的主函数作为默认的启动函数调用执行,但是,如果

JS基础知识回顾:在HTML中使用JavaScript

想HTML页面中插入JavaScript的主要方法就是使用<script>元素. HTML4.01当中为<script>元素定义了下列6个属性: language(已废弃):原来用于表示编写代码使用的脚本语言,如JavaScript.JavaScript1.2.VBScript等,由于大多数浏览器会忽略此属性,因此就没有必要再用了: type(可选):可以看成是language的替代属性,表示编写代码使用的脚本语言的内容类型,也被称作MIME类型,在未指定此属性的情况下会被默认为t

JS基础知识回顾:ECMAScript的语法(一)

任何语言的核心都必然会描述这门语言最基本的工作原理,而描述的内容通常都要涉及这门语言的语法.操作符.数据类型.内置功能等用于构建复杂解决方案的基本概念. ECMAScript中的一切变量.函数名.操作符都区分大小写. ECMAScript的标识符要符合下列规则:第一个字符必须是字母.下划线或美元符号:其他字符可以是字母.下划线.美元符号或数字. 标识符中的字母也可以包含扩展的ASCII或Unicode字母字符,但是并不推荐. 按照惯例,ECMAScript标识符采用驼峰大小写的格式来书写,尽管没

概率与统计 知识回顾(二) 一维随机变量及概率分布

1 随机变量的概念 顾名思义,随机变量就是“其值随机会而定”的变量.随机变量的反面是“确定性变量”,即其值遵循某种严格的规律的变量,比如从北京到上海的距离.但是从绝对意义上讲,许多通常视为确定性变量的量,本质上都有随机性,只是由于随机性干扰不大,以至在所要求的精度之内,不妨把经作为确定性变量来处理. 根据随机变量其可能取的值的全体的性质,可以把随机变量分为2大类,一类是离散型随机变量:一类是连续型随机变量.但是连续型变量这个概念只是数学上的抽象,因为任何量都有单位,都只能在该单位下量到一定的精度

JS基础知识回顾:引用类型(六)

ECMA-262对内置对象的定义是:由ECMAScript实现提供的.不依赖于宿主环境的对象,这些对象在ECMAScript程序执行之前就已经存在了. 开发人员不必显式的实例化内置对象,因为他们已经实例化了. 前面我们已经介绍了大多数内置对象,如Object.Array.String,ECMA-262还定义了两个单体内置对象:Global和Math. Global对象可以说是ECMAScript中最特别的一个对象了,因为不管你从什么角度上看,这个对象都是不存在的. 实际上并没有全局变量或全局属性

Event事件详解

首先提到event,先要明白event的产生,也要先明白焦点,什么是焦点.焦点 : 使浏览器能够区分用户输入的对象,当一个元素有焦点的时候,那么他就可以接收用户的输入. 我们可以通过一些方式给元素设置焦点.而并不是所有元素都能够接收焦点的,能够响应用户操作的元素才有焦点.例如: <input type="text" /> <a href="http://www.baidu.com">百度</a> 说到input,平时用的较多的是o