首先,事件并不是特殊的委托,它本质上是委托字段的一个包装器(类似字段和属性的关系),对外界隐藏了委托实例的大部分功能,仅暴露 添加/移除事件处理器的功能。
- 事件的完整声明格式:
// 当委托用来约束事件时,要以“委托名+EventHandler”命名,两个参数分别是事件的发送者和事件所传递的通知信息
public delegate void OrderEventHandler(Customer customer, OrderEventArgs e);
// 事件发送者
public class Customer
{
// 完整格式声明一个事件 OrderEvent
private OrderEventHandler orderEventHandler; // 先声明一个委托类型的字段,用来保存事件处理器
public event OrderEventHandler OrderEvent // 再声明一个事件,用来访问委托类型的字段
{
//事件的访问器,只有add和remove两个访问器,所以在外部,只能订阅和取消订阅事件,不能调用事件
add => orderEventHandler += value;
remove => orderEventHandler -= value;
}
}
// 事件传递的信息
// 微软规定事件信息类都应该继承EventArgs基类,原因在下文
public class OrderEventArgs : EventArgs
{
public string DishName { get; set; } //菜名
public int Count { get; set; } //份数
}
-
语法糖:字段式声明事件(field-like)
这种格式看起来像是声明了一个委托类型的字段,并用event关键字修饰,但实际上是声明了一个委托。编译器会自动为事件生成一个对应的委托类型的字段,然后在事件访问器中调用委托字段。
public class Customer
{
// 格式:public event 作为约束的委托类型 事件名
public event OrderEventHandler OrderEvent2;
}
-
使用EventHandler声明事件
EventHandler是微软定义的一个委托,其定义如下:
public delegate void EventHandler(object sender, EventArgs e);
可以看到它的第二个参数就是EventArgs类,如果我们在生命事件消息类时,统一按照微软的规定,继承了EventArgs类,那么就可以很方便地使用EventHandler来声明事件:
public class Customer
{
public event EventHandler OrderEvent; //使用EventHandler声明事件
public void OnOrder()
{
OrderEventArgs e = new OrderEventArgs { DishName = "鱼香肉丝", Count = 2 };
OrderEvent?.Invoke(this, e);
}
}
public class Waiter
{
// 事件处理器,参数要与EventHandler中定义的相同
public void Action(object sender, EventArgs e)
{
// 使用 is 关键字类型转换
if (sender is Customer customer && e is OrderEventArgs ea)
{
Debug.Log($"服务员:您点了{ea.Count}份{ea.DishName}");
}
}
}
- 使用泛型委托定义事件
使用微软定义的EventHandler<TEventArgs>来声明事件,这样事件消息类型就不用继承EventArgs,事件处理器中也不用对参数进行类型转换。
public event EventHandler<OrderEventArgs> OrderEvent;