为了简化自定义方法的构建来为委托调用列表增加和删除方法,C#提供了 event 关键字。在编译器处理event关键字的时候,它会自动提供注销方法以及委托类型任何必要的成员变量。这些委托成员变量总是声明为private的。所以不能直接从触发事件的对象来访问成员。
定义一个事件分两步:
1. 定义一个委托类型,包含事件触发时要调用的方法。
2. 通过 C# event 关键字用相关的委托来声明事件。
创建一个Car类,可以发送CarIsBroken(), OverSpeedAlarm(超速警告)事件。
// 创建一个委托用于对Car事件的响应处理。 public delegate void CarEngineHandler(string msg); // Car类可以发送的事件 public event CarEngineHandler eCarIsBroken; public event CarEngineHandler eOverSpeedAlarm;
实际上event会扩展为两个隐藏的公共方法,一个带add_前缀,一个带remove_前缀
例如: OverSpeedAlarm事件产生两个隐藏的方法:add_OverSpeedAlarm(),remove_OverSpeedAlarm().
监听传入的事件
C# 事件简化了注册调用者事件处理程序的操作,无需指定自定义辅助方法,调用者仅需使用+=,-=操作符。(操作符在后台触发正确的add_xxx()或remove_xxx()方法)。
namespace ConsoleApplication1 { class Program { public class Car { // 属性 public string CarName { get; set; } public int CurrentSpeed { get; set; } public int MaxSpeed { get; set; } // 成员 private bool carIsBroken; // 构造函数 public Car() { MaxSpeed = 180; } public Car(string name, int maxSpd, int curSpd) { CarName = name; CurrentSpeed = curSpd; MaxSpeed = maxSpd; //carIsBroken = false; } // 创建一个委托用于对Car事件的响应处理。 public delegate void CarEngineHandler(string msg); // Car类可以发送的事件 public event CarEngineHandler eCarIsBroken; public event CarEngineHandler eOverSpeedAlarm; public void Accelerate(int delta) { // 如果汽车已坏,触发eCarIsBroken事件 if (carIsBroken) { if (eCarIsBroken != null) // 触发事件! { eCarIsBroken("Car is broken,can't drive now!"); } } else { CurrentSpeed += delta; } // 超速提醒 if (20 == MaxSpeed - CurrentSpeed && eCarIsBroken != null) // 触发事件! { eOverSpeedAlarm("Alarm: Going too fast, drive slowly!"); } if (CurrentSpeed >= MaxSpeed) { carIsBroken = true; } else { Console.WriteLine("CurrentSpeed = {0}", CurrentSpeed); } } } public static void TheCarIsBroken(string msg) { Console.WriteLine(msg); } public static void TheCarIsOverSpeed(string msg) { Console.WriteLine(msg); } static void Main(string[] args) { Car myCar = new Car("Audio Q5", 200, 60); // 注册事件处理程序 //myCar.eOverSpeedAlarm += new Car.CarEngineHandler(TheCarIsOverSpeed); myCar.eOverSpeedAlarm += TheCarIsOverSpeed; myCar.eCarIsBroken += TheCarIsBroken; for (int i = 0; i < 12; i++) { myCar.Accelerate(20); } Console.ReadLine(); } } }
创建自定义的事件参数
对Car类可以进行改进,以符合微软推荐的事件模式。即
- 第一个参数是System.Object. 表示对发送事件的对象,如Car类的引用。
- 第二个参数是派生自EventArgs(基类)的子类型。表示与该事件相关的信息。
对于简单的事件来说,我们可以传递一个EventArgs的实例,如果要传递自定义数据,就需要构建一个派生自EventArgs的类。本例中,我们构建一个CarEventArgs的类,用于传递字符串。
// 利用EventArgs的派生类,来传递数据。 public class CarEventArgs : EventArgs { public readonly string msg; public CarEventArgs(string message) { msg = message; } }
并修改委托.(调整入口参数),和修改事件触发。
//eCarIsBroken("Car is broken,can't drive now!"); eCarIsBroken(this,new CarEventArgs("Car is broken,can't drive now!"));
全部程序如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApplication1 { class Program { public class Car { // 属性 public string CarName { get; set; } public int CurrentSpeed { get; set; } public int MaxSpeed { get; set; } // 成员 private bool carIsBroken; // 构造函数 public Car() { MaxSpeed = 180; } public Car(string name, int maxSpd, int curSpd) { CarName = name; CurrentSpeed = curSpd; MaxSpeed = maxSpd; //carIsBroken = false; } // 创建一个委托用于对Car事件的响应处理。 //public delegate void CarEngineHandler(string msg); public delegate void CarEngineHandler(object sender, CarEventArgs e); // Car类可以发送的事件 public event CarEngineHandler eCarIsBroken; public event CarEngineHandler eOverSpeedAlarm; public void Accelerate(int delta) { // 如果汽车已坏,触发eCarIsBroken事件 if (carIsBroken) { if (eCarIsBroken != null) // 触发事件! { //eCarIsBroken("Car is broken,can't drive now!"); eCarIsBroken(this,new CarEventArgs("Car is broken,can't drive now!")); } } else { CurrentSpeed += delta; } // 超速提醒 if (20 == MaxSpeed - CurrentSpeed && eCarIsBroken != null) // 触发事件! { //eOverSpeedAlarm("Alarm: Going too fast, drive slowly!"); eOverSpeedAlarm(this,new CarEventArgs("Alarm: Going too fast, drive slowly!")); } if (CurrentSpeed >= MaxSpeed) { carIsBroken = true; } else { Console.WriteLine("CurrentSpeed = {0}", CurrentSpeed); } } } // 利用EventArgs的派生类,来传递数据。 public class CarEventArgs : EventArgs { public readonly string msg; public CarEventArgs(string message) { msg = message; } } public static void TheCarIsBroken(object sender, CarEventArgs e) { Console.WriteLine("{0}:{1}",sender, e.msg); } public static void TheCarIsOverSpeed(object sender, CarEventArgs e) { Console.WriteLine("{0}:{1}", sender, e.msg); } static void Main(string[] args) { Car myCar = new Car("Audio Q5", 200, 60); // 注册事件处理程序 //myCar.eOverSpeedAlarm += new Car.CarEngineHandler(TheCarIsOverSpeed); myCar.eOverSpeedAlarm += TheCarIsOverSpeed; myCar.eCarIsBroken += TheCarIsBroken; for (int i = 0; i < 12; i++) { myCar.Accelerate(20); } Console.ReadLine(); } } }
输出:
CurrentSpeed = 80
CurrentSpeed = 100
CurrentSpeed = 120
CurrentSpeed = 140
CurrentSpeed = 160
ConsoleApplication1.Program+Car:Alarm: Going too fast, drive slowl
CurrentSpeed = 180
ConsoleApplication1.Program+Car:Car is broken,can't drive now!
ConsoleApplication1.Program+Car:Car is broken,can't drive now!
ConsoleApplication1.Program+Car:Car is broken,can't drive now!
ConsoleApplication1.Program+Car:Car is broken,can't drive now!
ConsoleApplication1.Program+Car:Car is broken,can't drive now!
==============================================
再继续前一篇软件组的例子。
事件中有两个角色,一个是发布者(Publisher),一个是订阅者(Subscriber). 在本例子中显然软件Lead 是发布者,而苦逼员工bill,和steven是订阅者。
老板发话开喊工作(发布事件),bill和steven由于订阅了老板的命名,在收到后就开始工作了(响应事件)
// Publisher. public class SoftwareLead { public delegate void assignSoftwareWork(); public event assignSoftwareWork onWork; public void DoWork() { if (onWork != null) { Console.WriteLine("Hey buddies, let's start working..."); onWork(); }; } }
public class SoftwareEngineer { private string engineerName; public SoftwareEngineer(string name) { this.engineerName = name; } public void UpdateFirmware() { Console.WriteLine("{0} is updating firmware...", this.engineerName); } public void FixBugs() { Console.WriteLine("{0} is fixing bugs...", this.engineerName); } // Subscriber public void ReceiveWork() { Console.WriteLine("Fk, work again?!"); this.UpdateFirmware(); this.FixBugs(); } }
static void Main(string[] args) { SoftwareLead fred = new SoftwareLead(); SoftwareEngineer bill = new SoftwareEngineer("Bill"); SoftwareEngineer steven = new SoftwareEngineer("Steven"); fred.onWork += bill.ReceiveWork; fred.onWork += steven.ReceiveWork; fred.DoWork(); }
显然,当Fred 开始DoWork的时候, OnWork 事件被触发,同时Bill,Steven两位小弟收到了事件,开始干活。
输出如下:
Hey buddies, let's start working... Fk, work again?! Bill is updating firmware... Bill is fixing bugs... Fk, work again?! Steven is updating firmware... Steven is fixing bugs...