以下两行代码几乎是等价的:
public event Action<EmployeeEventAgs> Leave;
相比:
public event EventHandler<EmployeeEventAgs> Leave;
区别在于事件处理方法的签名。如果您对动作使用第一种方法,您可以:
public void LeaveHandler(EmployeeEventAgs e) { ... }
然后是这个:
obj.Leave += LeaveHandler;
使用第二种方法,LeaveHandler 的签名需要不同:
public void LeaveHandler(object sender, EmployeeEventAgs e) { ... }
非常重要注意,在这两种情况下,event 关键字都用于声明事件成员。以这种方式声明的事件成员不仅仅是类的一个字段,尽管它看起来好像是。相反,编译器将其创建为 事件属性1。事件属性类似于常规属性,只是它们没有get 或set 访问器。编译器允许它们仅用于 += 和 -= 分配的左侧(添加或删除事件处理程序)。无法覆盖已分配的事件处理程序,或在声明它的类之外调用事件。
如果两个示例中缺少 event 关键字,您可以执行以下操作而不会出现错误或警告:
obj.Leave = LeaveHandler;
这将删除所有已注册的处理程序并将它们替换为LeaveHandler。
另外,你也可以执行这个调用:
obj.Leave(new EmployeeEventAgs());
如果您打算创建事件,则上述两种情况被视为反模式。事件应仅由所有者对象调用,并且不应允许无法追踪删除订阅者。 event 关键字是 .NET 的编程结构,可帮助您坚持正确使用事件。
考虑到上述情况,我相信很多人都会坚持使用EventHandler 方法,因为如果没有event 关键字,则不太可能使用EventHandler。动作有更广泛的使用范围,它们在使用时看起来不像事件那样自然。当然,后者是个人意见,因为事件处理程序方法可能在我自己的编码实践中变得过于硬性。不过,如果动作使用得当,将它们用于事件并不是犯罪。
1 事件属性是编译器在看到这样的代码时自动生成的:
event EventHandler SomeEvent
变成如下代码大致相同:
private EventHandler _someEvent; // notice the lack of the event keyword!
public event EventHandler SomeEvent
{
add { _someEvent += value; }
remove { _someEvent -= value; }
}
我们这样写的事件调用:
this.SomeEvent(sender, args);
转换成这个:
this._someEvent(sender, args);