事件只是添加方法和删除方法的组合,两者都采用相同委托类型的单个参数。事件对传入委托的作用完全取决于实现。
Add
处理程序中收到的事件委托最常见的事情是Delegate.Combine
使用先前添加的委托(如果有),但也有一些其他可能性:
如果一个对象将支持多种事件,但许多实例的大多数订阅者为零,则可以将委托添加到表中。许多 WinForms 事件都是这样做的。
如果希望允许订阅者使用逆变委托类型,可以将接收到的委托放入List<>
委托或持有委托对象的数组、链表中。
如果事件表示某些类型的对象会触发,但特定实例永远不会触发,则事件可能会简单地丢弃委托。例如,考虑一个ObservableFoo
具有抽象更改通知事件的抽象类,以及一个约定,只要实例的属性发生更改,它将调用所有传入的委托;从它派生的ImmutableFoo
类可以接受订阅请求,但由于它永远不会改变,所以它永远不必调用传入的委托(或对它们做任何其他事情)并且可以简单地丢弃它们。
由于事件是一对以委托类型作为参数的方法,因此每个事件都必须“根据定义”使用委托作为其参数类型。所有重要的事件都必须以某种形式存储传入的委托。接受多个订阅的最常见方法是将它们组合成一个多播委托(我不喜欢这种设计,顺便说一句,但这是最常见的);可以使用其他方法,但是要使用传入委托的事件必须以某种方式存储它们。
顺便说一句,在 C# 中声明事件有两种方法:一种可以显式提供添加/删除处理程序,在这种情况下,编译器将使用这些处理程序创建一个事件。也可以只提供事件名称和委托类型,在这种情况下,编译器将创建一个具有指定名称和范围的事件,一个具有相同名称和适当委托类型的私有变量,以及添加/删除的线程安全方法或从指示的变量中删除事件。表单eventName += something;
或eventName -= something;
将作为对“添加”或“删除”方法的调用处理的语句;该名称的所有其他用途将指代委托人。请注意,在旧版本的 C# 中,在类中使用 and 将eventName += something;
使用andeventName -= something;
+=
-=
委托上的操作不是线程安全的,但较新的版本已经改变了这种行为。