C#的Event事件示例小白级剖析

1、委托Delegate

首先说一下delegate委托,委托是将方法作为参数进行传递。

// 定义了一个委托类型public delegate void MyDelegate(int num);// 定义了一个啥也不干的委托实例public MyDelegate m_delegate = _ => {};// 定义了一个和委托相同格式的方法public void MyFun(int num){Console.WriteLine(num);};  // 添加新的委托m_delegate += MyFun;// 执行任务m_delegate(2);

2、基于委托的发布/订阅模式

基于上例,对于如下的操作:

m_delegate += MyFun1;

m_delegate += MyFun2;

....

m_delegate(1);

这是一个委托的多播操作,一连串的任务会一起执行。

此时换一个思维,假如把+=操作看成是订阅操作。m_delegate(1)是发布,1可以看做是一个message,可以是int,也可以是string。这样就构成了一个发布/订阅模式。

当m_delegate(1)发布执行时,委托的多播会让所有订阅函数执行。

所以订阅者只需要把委托格式的函数告诉发布者(+=注册进去),当发布者发布时,所有的订阅者就相当于收到了消息。

下面写一个基于委托的发布/订阅模式:

#define DEBUG3using System;
using System.Diagnostics;namespace ConsoleApp1
{public delegate void SayGate(int num);public class Publisher{// 定义委托public SayGate SayGateHandler;// 触发任务public void OnTrigger(int num){// 触发任务SayGateHandler(num);}}public class Subscriber{public void Subscribe(Publisher publisher){// 订阅publisher.SayGateHandler += SayHello;}public void SayHello(int num){Console.WriteLine("subscribe1: " + num);}}public class Subscriber2{public void Subscribe(Publisher publisher){// 订阅publisher.SayGateHandler += SayHello;}public void SayHello(int num){Console.WriteLine("subscribe2: " + num);}}internal class Program{static void Main(string[] args) {Publisher publisher = new Publisher();Subscriber subscriber = new Subscriber();subscriber.Subscribe(publisher);Subscriber2 subscriber2 = new Subscriber2();subscriber2.Subscribe(publisher);Console.ReadLine();publisher.OnTrigger(1);Console.ReadLine();}}
}

执行后会显示:

subscribe1: 1
subscribe2: 1

3、存在的缺陷

假如有个订阅者干了坏事,把"+="写成了"=",比如:

此时执行后会显示:

subscribe2: 1

即只显示了一条。

4、事件Event

针对上面的缺陷,需要引入一种机制限制订阅者的行为。

在C#中,event是一种特殊的委托,特殊之处为:订阅者只能通过"+="和"-="订阅或取消。发布者仍然可以进行"="操作。

当将SayGateHandler定义为event之后,订阅者2"="方式的订阅提示失败。

错误信息为:事件"Publisher.SayGateEvent"只能出现在+=或-=的左边(从类型“Publisher“中使用时除外)

新程序如下:

namespace ConsoleApp1
{public delegate void SayGate(int num);public class Publisher{// 定义委托public event SayGate SayGateHandler;// 触发任务public void OnTrigger(int num){// 触发任务SayGateHandler(num);}}public class Subscriber{public void Subscribe(Publisher publisher){// 订阅publisher.SayGateHandler += SayHello;}public void SayHello(int num){Console.WriteLine("subscribe1: " + num);}}public class Subscriber2{public void Subscribe(Publisher publisher){// 订阅publisher.SayGateHandler += SayHello;}public void SayHello(int num){Console.WriteLine("subscribe2: " + num);}}internal class Program{static void Main(string[] args) {Publisher publisher = new Publisher();Subscriber subscriber = new Subscriber();subscriber.Subscribe(publisher);Subscriber2 subscriber2 = new Subscriber2();subscriber2.Subscribe(publisher);Console.ReadLine();publisher.OnTrigger(1);Console.ReadLine();}}
}

5、存在的缺陷2

以上程序有2个订阅者,但是假如没有订阅者,此时发布后会怎么样?

将以上代码注释后做测试,报错信息如下:

此处报错的意思是:SayGameHandler没有实例化。

有两种解决方案:

1)发布者实例化一个空的委托,

public event SayGate SayGateHandler = _ => { };

2)触发事件时检测下是否实例化,

// 触发任务

SayGateHandler?.Invoke(num);

两种方法选择一种即可。

最后一个完整的Event示例如下:

namespace ConsoleApp1
{public delegate void SayGate(int num);public class Publisher{// 定义委托public event SayGate SayGateHandler;// 触发任务public void OnTrigger(int num){// 触发任务SayGateHandler?.Invoke(num);}}public class Subscriber{public void Subscribe(Publisher publisher){// 订阅publisher.SayGateHandler += SayHello;}public void SayHello(int num){Console.WriteLine("subscribe1: " + num);}}public class Subscriber2{public void Subscribe(Publisher publisher){// 订阅publisher.SayGateHandler += SayHello;}public void SayHello(int num){Console.WriteLine("subscribe2: " + num);}}internal class Program{static void Main(string[] args) {Publisher publisher = new Publisher();Subscriber subscriber = new Subscriber();subscriber.Subscribe(publisher);Subscriber2 subscriber2 = new Subscriber2();subscriber2.Subscribe(publisher);Console.ReadLine();publisher.OnTrigger(1);Console.ReadLine();}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/464197.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android 使用ninja加速编译的方法

ninja的简介 随着Android版本的更迭,makefile体系逐渐增多,导致make单编模块的时间越来越长,每次都需要半个小时甚至更长时间,其原因为每次make都会重新加载所有mk文件,再生成ninja编译,此完整过程十分耗时…

VSCode 1.82之后的vscode server离线安装

概述 因为今天在公司开发项目的时候,需要离线配置vscode远程开发环境, 根据参考链接1配置了一遍,不管怎么重启,VSCODE都还是提示下载vscode server,后面在官方issue上找到了解决方案 解决方案 修改Remote SSH的配置…

什么是 OpenTelemetry?

OpenTelemetry 定义 OpenTelemetry (OTel) 是一个开源可观测性框架,允许开发团队以单一、统一的格式生成、处理和传输遥测数据(telemetry data)。它由云原生计算基金会 (CNCF) 开发,旨在提供标准化协议和工具,用于收集…

缓存、注解、分页

一.缓存 作用:应用查询上,内存中的块区域。 缓存查询结果,减少与数据库的交互,从而提高运行效率。 1.SqlSession 缓存 1. 又称为一级缓存,mybatis自动开启。 2. 作用范围:同一…

AI打造超写实虚拟人物:是科技奇迹还是伦理挑战?

内容概要 在这个科技飞速发展的时代,超写实虚拟人物仿佛从科幻小说中走进了我们的日常生活。它们以生动的形象和细腻的动作,不仅在影视、广告和游戏中吸引了无数目光,更让我们对AI技术的未来充满了期待和疑惑。这些数字化身在逼真的外貌下&a…

CODESYS可视化星三角降压启动程序控制电气动画图

#一个用CODESYS可视化做的星三角降压启动程序控制电气动画图# 前言: 关于星三角降压启动控制,作为电气行业入门的必备知识点,涉及到电机本身特性导致的电压,电流(转矩),功率和转速等一系列的关系和变化,以及星型和三角形的绕组方式。本篇我们使用CODESYS结合程序和可视…

物联网赋能的人工智能图像检测系统

一、引言 在数字化时代,物联网(IoT)技术已经成为我们生活中不可或缺的一部分,极大地优化了我们的交通出行和医疗服务。物联网的核心优势在于其卓越的连接能力,它能够构建和连接庞大的资源数据库,为智能化图…

软件架构演变:从单体架构到LLM链式调用

0 前言 软件架构——我们数字世界的蓝图——自20世纪中叶计算机时代诞生以来,已经发生了巨大演变。 20世纪60年代和70年代早期,以大型主机和单体软件为主导。而今天,数字领域已完全不同,运行在由云计算、API连接、AI算法、微服务…

Claude 3.5 Sonnet模型新增了PDF支持功能

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…

【每日一题】LeetCode - 三数之和

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k ,同时还满足 nums[i] nums[j] nums[k] 0 。请你返回所有和为 0 且不重复的三元组。 注意:答案中不可以包含重复的三元组。 示例 示…

基于 Canal + Elasticsearch 的业务操作日志解决方案

一、问题来源 在日常的业务系统中,操作日志是不可或缺的一部分。它能帮助我们追踪用户的操作行为,记录关键数据的变更,甚至在必要时支持操作回滚。最近,我们接到客户的需求,希望在系统中实现一个业务操作日志管理的功能…

Python并发编程库:Asyncio的异步编程实战

Python并发编程库:Asyncio的异步编程实战 在现代应用中,并发和高效的I/O处理是影响系统性能的关键因素之一。Python的asyncio库是专为异步编程设计的模块,提供了一种更加高效、易读的并发编程方式,适用于处理大量的I/O密集型任务…

【Vue项目1】第一篇

Vue项目1学习第一篇 01. 环境配置介绍和项目搭建02. Router路由配置引入03. ElementPlus引入和按需加载04. layout布局和菜单aside组件创建05. aside样式问题和treeMenu组件拆分06. treeMenu组件递归实现 01. 环境配置介绍和项目搭建 (1)安装node.js …

WPF使用Prism框架首页界面

1. 首先确保已经下载了NuGet包MaterialDesignThemes 2.我们通过包的项目URL可以跳转到Github上查看源码 3.找到首页所在的代码位置 4.将代码复制下来&#xff0c;删除掉自己不需要的东西&#xff0c;最终如下 <materialDesign:DialogHostDialogTheme"Inherit"Ide…

Golang | Leetcode Golang题解之第524题通过删除字母匹配到字典里最长单词

题目&#xff1a; 题解&#xff1a; func findLongestWord(s string, dictionary []string) (ans string) {m : len(s)f : make([][26]int, m1)for i : range f[m] {f[m][i] m}for i : m - 1; i > 0; i-- {f[i] f[i1]f[i][s[i]-a] i}outer:for _, t : range dictionary …

无人机的就业前景怎么样?

无人机的就业前景在当前及未来一段时间内都非常广阔。随着低空经济的蓬勃发展&#xff0c;无人机在农业、公安、测绘、交通、应急救援、影视拍摄等多个领域得到了广泛应用&#xff0c;对无人机操控员和相关专业人才的需求也随之急剧增加。 一、无人机操控员的就业前景 1. 高需…

如何将钉钉新收款单数据高效集成到MySQL

钉钉数据集成到MySQL的技术案例分享 在企业信息化管理中&#xff0c;数据的高效流动和处理至关重要。本文将分享一个具体的系统对接集成案例&#xff1a;如何将钉钉平台上的新收款单&#xff08;收款退款单&#xff09;数据集成到MySQL数据库中&#xff0c;方案名称为“dd-新收…

批量修改图片大小+删除空白页+手写签名

插入图片右键设置大小 设置对象格式 高度&#xff0c;宽度同一 最后一张图片拖到最后 alt键一下吸附好 ctrla全选图片 对齐 纵向分布 删除空白页 前面有文字 CTRL删除键 上一页是表格 CTRLd 勾选隐藏文字 手写签名 手机拍摄签名 发到电脑 文档里插入图…

软设师知识点-计算机网络

计算机网络 在一台安装好TCP/IP协议的计算机上&#xff0c;当网络连接不可用时&#xff0c;为了测试编写好的网络程序&#xff0c;通常使用的目的主机IP地址127.0.0.1&#xff08;本地回送地址&#xff09; *网络设备 物理层的互传设备&#xff1a;中继器(用于扩展局域网网段…

40.第二阶段x86游戏实战2-初识lua

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 本人写的内容纯属胡编乱造&#xff0c;全都是合成造假&#xff0c;仅仅只是为了娱乐&#xff0c;请不要…