C#中事件的运行模式为"发布订阅模型",事件触发者称为"发布者",事件处理者称为"订阅者"
五个组成部分的关系为:
事件的拥有者拥有事件,事件的响应者订阅事件。当事件被触发后,事件的拥有者令事件通知事件的响应者,事件的响应者通过事件处理器处理事件
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; }
- }
事件基于委托,但不等同于委托