当前位置: 首页 > 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; }
}

结语

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

http://www.lryc.cn/news/305272.html

相关文章:

  • C语言:指针(一)
  • 【leetcode刷题之路】面试经典150题(3)——哈希表+区间
  • 群晖NAS DSM7.2.1安装宝塔之后无法登陆账号密码问题解决
  • 9、使用 ChatGPT 的 GPT 制作自己的 GPT!
  • 企业微信应用开发:使用Cpolar域名配置进行本地接口回调的调试指南
  • js 可选链运算符(?.)空值合并运算符(??)逻辑空赋值运算符(??=)
  • vue 手势解锁功能
  • 介绍 CI / CD
  • Stable Diffusion 3 Early Preview发布
  • 【解决(几乎)任何机器学习问题】:特征选择
  • 24 双非计算机秋招总结
  • 用友NC65与用友NCC对接集成NC65-凭证列表查询打通凭证新增
  • 【初中生讲机器学习】12. 似然函数和极大似然估计:原理、应用与代码实现
  • 【达梦数据库】查看pesg回滚段信息的视图和SQL
  • UML---活动图
  • 编程笔记 Golang基础 018 常量与变量
  • 如何使用Douglas-042为威胁搜索和事件应急响应提速
  • 华为配置WLAN AC和AP之间VPN穿越示例
  • 跨语言的序列化与反序列化
  • 软考-中级-系统集成2023年综合知识(三)
  • 五、使用脚手架
  • 抛弃chatgpt,使用微软的Cursor提升coding效率
  • uniapp插件uViewplus的使用(涉及TS下的问题)
  • google浏览器chrome无法访问localhost等本地虚拟域名的解决方法
  • (2.2w字)前端单元测试之Jest详解篇
  • 【C++私房菜】面向对象中的多态
  • (done) 什么是特征值和特征向量?如何求特征值的特征向量 ?如何判断一个矩阵能否相似对角化?
  • [rust] 11 所有权
  • MySQL安装
  • AI时代显卡如何选择,B100、H200、L40S、A100、H100、V100 含架构技术和性能对比