当前位置: 首页 > news >正文

C#_事件简述

事件模型简述

C#中事件的运行模式为"发布订阅模型",事件触发者称为"发布者",事件处理者称为"订阅者"

事件模型的五个组成部分

  1. 事件(成员)
  2. 事件的拥有者(类/对象)
  3. 事件的响应者(类/对象)
  4. 事件处理器(事件处理器的成员方法)
  5. 事件订阅(+= -=)

五个组成部分的关系为:

事件的拥有者拥有事件事件的响应者订阅事件。当事件被触发后,事件的拥有者事件通知事件的响应者事件的响应者通过事件处理器处理事件

事件示例:System.Timers.Timer

System.Timers.Timer是.NET提供的线程不安全的计时器类,此处介绍其Elapsed事件

System.Timers.Timer timer = new(1000);
// Elapsed事件 通过"+="订阅事件
timer.Elapsed += (sender, e) =>
{Console.WriteLine("System.Timers.Timer");
};
timer.Start();
Thread.Sleep(6000);
// 停止计时器
timer.Dispose();

间隔1S事件就会被触发一次,然后被事件处理器处理

事件的完整声明

private static void Main(string[] args)
{Customer customer = new();Waiter waiter = new();customer.Order += waiter.TakeOrder;customer.Think("Cake", "Medium");
}public class Customer
{private OrderEventHandler orderEventHandler; // 事件用于接收订阅的委托public event OrderEventHandler Order         // 事件{add{orderEventHandler += value;}remove{orderEventHandler -= value;}}public double Bill { get; set; }public void Think(string dishName, string size){Console.WriteLine("Customer: I need {0} {1}", size, dishName);OnOrder("Cake", "Medium");}protected void OnOrder(string dishName, string size){if (orderEventHandler != null){OrderEventArgs args = new();args.DishName = dishName;args.Size = size;orderEventHandler(this, args);}}
}
public class Waiter
{public void TakeOrder(Customer customer, OrderEventArgs e){Console.WriteLine("I will serve you the dish - {0} {1}", e.Size, e.DishName);double basePrice = 10;switch (e.Size){case "small":basePrice *= 0.5;break;case "large":basePrice *= 1.5;break;default:break;}customer.Bill += basePrice;Console.WriteLine("You need to pay ${0}", customer.Bill);}
}
// 依据.net规范, 类的作用是传递事件信息(EventArgs)时, 需在声明时添加EventArgs后缀, 并实现EventArgs类
public class OrderEventArgs : EventArgs
{public string DishName { get; set; }public string Size { get; set; }
}
// 依据.net规范, 委托的作用是处理事件时, 需要在声明时添加EventHandler后缀
public delegate void OrderEventHandler(Customer customer, OrderEventArgs e);

上述代码中,事件的五个组成部分:customer是事件的拥有者,waiter是事件的响应者,customer.Order是事件,waiter.TakeOrder是事件处理器,"+="是事件的订阅。此外,orderEventHandler是事件用于接收订阅的委托,customer.Think是事件的触发者

需要说明的是:

1.依据.net规范,类的作用是传递事件信息(EventArgs)时,需在声明时添加EventArgs后缀,并实现EventArgs类(上述代码中的OrderEventArgs类)

2.依据.net规范,委托的作用是处理事件时,需要在声明时添加EventHandler后缀(上述代码中的OrderEventHandler委托)

事件的简略声明

简略声明

从形式上看事件似乎是字段,但实际上不是。事件之于委托,类似属性之于字段

事件只能出现在+=或-=操作符左侧,但OnOrder函数的if语句中却出现在了!=操作符左侧,原因是此处为C#语法糖(简略声明下,无显式的委托字段,只能如此。Order(this, args)也是出于同样的原因)

public class Customer
{public event OrderEventHandler Order; // 事件public double Bill { get; set; }public void Think(string dishName, string size){Console.WriteLine("Customer: I need {0} {1}", size, dishName);OnOrder("Cake", "Medium");}protected void OnOrder(string dishName, string size){if (Order != null){OrderEventArgs args = new();args.DishName = dishName;args.Size = size;Order(this, args);}}
}

完整声明

public class Customer
{private OrderEventHandler orderEventHandler; // 事件用于接收订阅的委托public event OrderEventHandler Order         // 事件{add{orderEventHandler += value;}remove{orderEventHandler -= value;}}public double Bill { get; set; }public void Think(string dishName, string size){Console.WriteLine("Customer: I need {0} {1}", size, dishName);OnOrder("Cake", "Medium");}protected void OnOrder(string dishName, string size){if (orderEventHandler != null){OrderEventArgs args = new();args.DishName = dishName;args.Size = size;orderEventHandler(this, args);}}
}

实际上大多数情况下可以直接使用C#提供的事件委托(EventHandler)来声明事件,无需自己声明事件委托

但是需要注意EventHandler委托的参数格式是(object? sender, EventArgs e),被委托的函数中需要做里氏转换(此即为何自定义的XXXEventArgs类最好派生自EventArgs类的原因)

private static void Main(string[] args)
{Customer customer = new();Waiter waiter = new();customer.Order += waiter.TakeOrder;customer.Think("Cake", "Medium");
}public class Customer
{public event EventHandler Order;public double Bill { get; set; }public void Think(string dishName, string size){Console.WriteLine("Customer: I need {0} {1}", size, dishName);OnOrder("Cake", "Medium");}protected void OnOrder(string dishName, string size){if (Order != null){OrderEventArgs args = new();args.DishName = dishName;args.Size = size;Order(this, args);}}
}
public class Waiter
{public void TakeOrder(Object customer, EventArgs e){// 里氏转换Customer customer_ = customer as Customer;OrderEventArgs e_ = e as OrderEventArgs;Console.WriteLine("Waiter: I will serve you the dish - {0} {1}", e_.Size, e_.DishName);double basePrice = 10;switch (e_.Size){case "Small":basePrice *= 0.5;break;case "Large":basePrice *= 1.5;break;default:break;}customer_.Bill += basePrice;Console.WriteLine("Waiter: You need to pay ${0}", customer_.Bill);}
}
// 依据.net规范, 类的作用是传递事件信息(EventArgs)时, 需在声明时添加EventArgs后缀, 并实现EventArgs类
public class OrderEventArgs : EventArgs
{public string DishName { get; set; }public string Size { get; set; }
}

结语

事件基于委托,但不等同于委托 

相关文章:

C#_事件简述

事件模型简述 C#中事件的运行模式为"发布订阅模型",事件触发者称为"发布者",事件处理者称为"订阅者" 事件模型的五个组成部分 事件(成员)事件的拥有者(类/对象)事件的响应…...

C语言:指针(一)

目录 1.内存和地址2. 指针变量和地址2.1 取地址操作符(&)2.2 指针变量和解引用操作符(*)2.2.1 指针变量2.2.2 解引用操作符(*) 2.3 指针变量的大小 3.指针变量的类型和意义3.1 指针的解引用3.2 指针 -指…...

【leetcode刷题之路】面试经典150题(3)——哈希表+区间

文章目录 5 哈希表5.1 【哈希表】赎金信5.2 【数学】同构字符串5.3 【数学】单词规律5.4 【哈希表】有效的字母异位词5.5 【哈希表】字母异位词分组5.6 【双指针】两数之和5.7 【数学】快乐数5.8 【哈希表】219. 存在重复元素 II5.9 【数学】最长连续序列 6 区间6.1 【数学】汇…...

群晖NAS DSM7.2.1安装宝塔之后无法登陆账号密码问题解决

宝塔的安装就不在这赘述了,只说下,启动之后默认账号密码无法登陆的问题。 按照上面给出的账号密码,无法登陆 然后点忘记密码,由于是docker安装的,根目录下没有/www/server/panel 。 也没有bt命令 要怎么修改呢。 既然…...

9、使用 ChatGPT 的 GPT 制作自己的 GPT!

使用 ChatGPT 的 GPT 制作自己的 GPT! 想用自己的 GPT 超越 GPT ChatGPT 吗?那么让我们 GPT GPT 吧! 山姆 奥特曼利用这个机会在推特上宣传 GPTs 的同时还猛烈抨击了埃隆的格罗克。 GPTs概览 他们来了! 在上周刚刚宣布之后,OpenAI 现在推出了其雄心勃勃的新 ChatGPT…...

企业微信应用开发:使用Cpolar域名配置进行本地接口回调的调试指南

文章目录 1. Windows安装Cpolar2. 创建Cpolar域名3. 创建企业微信应用4. 定义回调本地接口5. 回调和可信域名接口校验6. 设置固定Cpolar域名7. 使用固定域名校验 企业微信开发者在应用的开发测试阶段,应用服务通常是部署在开发环境,在有数据回调的开发场…...

js 可选链运算符(?.)空值合并运算符(??)逻辑空赋值运算符(??=)

可选链运算符(?.)允许读取位于连接对象链深处的属性的值,而不必明确验证链中的每个引用是否有效。?. 运算符的功能类似于 . 链式运算符,不同之处在于,在引用为空 (nullish ) (null 或者 undefined) 的情况下不会引起…...

vue 手势解锁功能

效果 实现 <script setup lang"ts"> const canvasRef ref<HTMLCanvasElement>() const ctx ref<CanvasRenderingContext2D | null>(null) const width px2px(600) const height px2px(700) const radius ref(px2px(50))const init () > …...

介绍 CI / CD

目录 一、介绍 CI / CD 1、为什么要 CI / CD 方法简介 1、持续集成 2、持续交付 3、持续部署 2、GitLab CI / CD简介 3、GitLab CI / CD 的工作原理 4、基本CI / CD工作流程 5、首次设置 GitLab CI / CD 6、GitLab CI / CD功能集 一、介绍 CI / CD 在本文档中&#x…...

Stable Diffusion 3 Early Preview发布

2月22日&#xff0c;Stability AI 发布了 Stable Diffusion 3 early preview&#xff0c;这是一种开放权重的下一代图像合成模型。据报道&#xff0c;它继承了其前身&#xff0c;生成了详细的多主题图像&#xff0c;并提高了文本生成的质量和准确性。这一简短的公告并未附带公开…...

【解决(几乎)任何机器学习问题】:特征选择

当你创建了成千上万个特征后&#xff0c;就该从中挑选出⼏个了。但是&#xff0c;我们绝不应该创建成百上千个⽆⽤的特征。特征过多会带来⼀个众所周知的问题&#xff0c;即 "维度诅咒"。如果你有很多特征&#xff0c;你也必须有很多训练样本来捕捉所有特征。什么是 …...

24 双非计算机秋招总结

引言 我整理了一份 10w 字数的前端技术文档&#xff08;飞书&#xff09;&#xff0c;地址&#xff1a;https://qx8wba2yxsl.feishu.cn/docx/Vb5Zdq7CGoPAsZxMLztc53E1n0k?fromfrom_copylink&#xff0c;欢迎对前端感兴趣的同学查看、共建、分享。 PS&#xff1a;我是一名大四…...

用友NC65与用友NCC对接集成NC65-凭证列表查询打通凭证新增

用友NC65与用友NCC对接集成NC65-凭证列表查询打通凭证新增 数据源平台:用友NC65 用友NC是为集团与行业企业提供的全线管理软件产品&#xff0c;由亚太本土最大的企业管理软件提供商用友公司研发提供&#xff0c;用友NC率先采用J2EE架构和先进开放的集团级开发平台UAP&#xff0…...

【初中生讲机器学习】12. 似然函数和极大似然估计:原理、应用与代码实现

创建时间&#xff1a;2024-02-23 最后编辑时间&#xff1a;2024-02-24 作者&#xff1a;Geeker_LStar 你好呀~这里是 Geeker_LStar 的人工智能学习专栏&#xff0c;很高兴遇见你~ 我是 Geeker_LStar&#xff0c;一名初三学生&#xff0c;热爱计算机和数学&#xff0c;我们一起加…...

【达梦数据库】查看pesg回滚段信息的视图和SQL

一些达梦回滚段是使用情况的查询SQL&#xff0c;供排查“回滚记录版本太旧&#xff0c;无法获取用户记录” 等类似问题时使用 视图名说明主库备库v$pseg_items显示回滚系统中当前回滚项信息&#xff08;回滚线程的工作信息&#xff09;总行数WORKER_THREADS1查询 no rowsv$pseg…...

UML---活动图

活动图概述 活动图&#xff08;Activity Diagram&#xff09;是UML&#xff08;Unified Modeling Language&#xff0c;统一建模语言&#xff09;中的一种行为建模工具&#xff0c;主要用于描述系统或业务流程中的一系列活动或操作。活动图通常用于描述用例中的行为&#xff0c…...

编程笔记 Golang基础 018 常量与变量

编程笔记 Golang基础 018 常量与变量 一、常量常量的定义iota特性 二、变量变量定义变量作用域零值与初始化类型转换注意事项 三、重要性 常量&#xff0c;就是在程序编译阶段就确定下来的值&#xff0c;而程序在运行时则无法改变该值。变量是程序的基本组成单位&#xff0c;用…...

如何使用Douglas-042为威胁搜索和事件应急响应提速

关于Douglas-042 Douglas-042是一款功能强大的PowerShell脚本&#xff0c;该脚本可以提升数据分类的速度&#xff0c;并辅助广大研究人员迅速从取证数据中筛选和提取出关键数据。 该工具能够搜索和识别Windows生态系统中潜在的安全漏洞&#xff0c;Douglas-042会将注意力放在…...

华为配置WLAN AC和AP之间VPN穿越示例

配置WLAN AC和AP之间VPN穿越示例 组网图形 图1 配置WLAN AC和AP之间VPN穿越示例组网图 业务需求组网需求数据规划配置思路配置注意事项操作步骤配置文件 业务需求 企业用户接入WLAN网络&#xff0c;以满足移动办公的最基本需求。且在覆盖区域内移动发生漫游时&#xff0c;不影响…...

跨语言的序列化与反序列化

在Java中实现跨语言的序列化与反序列化通常可以采用以下几种方式 使用标准的跨语言序列化格式 可以选择使用一些标准的跨语言序列化格式,例如JSON、XML、Protocol Buffers(ProtoBuf)等。这些格式都是跨语言的,可以方便地在不同的编程语言之间进行数据交换。在Java中,可以…...

HttpOnly Cookie 深度解析

一、什么是 HttpOnly Cookie HttpOnly 是一个可以附加在 Set-Cookie 响应头上的标志位&#xff08;flag&#xff09;。当一个 Cookie 被标记为 HttpOnly 后&#xff0c;客户端脚本&#xff08;如 JavaScript&#xff09;将无法通过 document.cookie 等 API 访问该 Cookie&…...

从PUMA560到你的项目:手把手教你将经典DH建模流程迁移到自定义机械臂

从PUMA560到自定义机械臂&#xff1a;DH建模实战迁移指南 当机械臂从教科书案例走向真实项目时&#xff0c;最令人头疼的莫过于面对一个全新构型却不知如何下手。本文将以工业界经典的PUMA560为跳板&#xff0c;拆解一套可迁移的DH建模方法论&#xff0c;带您跨越从理论到实践的…...

STM32F407通过SPI接口高效读写SD卡:CubeMX配置与底层驱动实战

1. SD卡基础与SPI通信原理 SD卡作为嵌入式系统中最常用的存储介质之一&#xff0c;其SPI模式因其接线简单、协议清晰而广受欢迎。先说说我实际项目中遇到的坑&#xff1a;曾经因为没理解清楚SPI模式下SD卡的初始化时序&#xff0c;导致整整两天卡在设备无法识别的困境里。 SD卡…...

智能路由器项目解析:基于策略路由实现多线路流量智能调度

1. 项目概述&#xff1a;一个“聪明”的路由器能做什么&#xff1f;最近在GitHub上看到一个挺有意思的项目&#xff0c;叫smart-router&#xff0c;作者是c0nSpIc0uS7uRk3r。光看名字&#xff0c;你可能会觉得这又是一个关于家庭网络优化的工具&#xff0c;但点进去仔细研究后&…...

Touchpoint:命令行工具集中管理工作上下文,提升开发效率

1. 项目概述&#xff1a;一个被低估的开发者效率工具如果你和我一样&#xff0c;日常开发工作需要在多个代码仓库、项目管理工具&#xff08;如Jira、Linear&#xff09;、文档平台&#xff08;如Confluence、Notion&#xff09;和沟通软件&#xff08;如Slack&#xff09;之间…...

百度网盘直链解析工具:告别限速,实现高速下载的Python解决方案

百度网盘直链解析工具&#xff1a;告别限速&#xff0c;实现高速下载的Python解决方案 【免费下载链接】baidu-wangpan-parse 获取百度网盘分享文件的下载地址 项目地址: https://gitcode.com/gh_mirrors/ba/baidu-wangpan-parse 在数字资源共享日益频繁的今天&#xff…...

终极指南:3步掌握yfinance金融数据获取与智能修复实战

终极指南&#xff1a;3步掌握yfinance金融数据获取与智能修复实战 【免费下载链接】yfinance Download market data from Yahoo! Finances API 项目地址: https://gitcode.com/GitHub_Trending/yf/yfinance yfinance是一个强大的Python库&#xff0c;能够从Yahoo! Finan…...

Arm Iris调试接口:架构设计与工程实践详解

1. Iris调试与追踪接口深度解析调试与追踪技术是嵌入式系统开发的核心支柱&#xff0c;而Arm的Iris接口代表了这一领域的最新进展。作为一名长期从事嵌入式调试工具开发的工程师&#xff0c;我将带您深入剖析这套接口的设计哲学与实战应用。1.1 接口架构设计理念Iris的架构设计…...

基于Kubernetes Lease构建分布式部署锁:解决CI/CD环境下的资源竞争

1. 项目概述&#xff1a;从“clawfight”看一场被遗忘的社区技术博弈看到“2019-02-18/clawfight”这个标题&#xff0c;很多人的第一反应可能是困惑。它不像一个标准的软件项目名&#xff0c;没有清晰的版本号&#xff0c;也没有指明具体的技术栈。但恰恰是这种看似随意的命名…...

Arm Iris组件参数化建模与调试实践

1. Arm Iris组件概述与核心价值Arm Iris组件是Fast Models仿真平台中的关键模块&#xff0c;它为芯片设计验证和软件开发提供了高度参数化的虚拟原型环境。作为一名长期从事Arm架构开发的工程师&#xff0c;我发现Iris组件的设计理念完美体现了"配置即硬件"的思想——…...