使用 EventArgs/EventArgs<T> 委托类型而不是其他类型的事件的好处

5
我了解使用带有签名 delegate void delegate_name(object sender, EventArgs e) 的委托类型的事件的好处。
a) 除了它可以为我们节省一些打字之外,我们使用已定义的委托类型 EventHandler/EventHandler<T> 而不是声明自己的带有签名 delegate void delegate_name(object sender, EventArgs e) 的委托类型还有其他原因吗?
b) 我能想到的使用预定义委托类型 EventArgs/EventArgs<T> 的另外两个原因是:
  • 使用特定事件(例如 event EventHandler my_event)的人将立即知道如何使用该事件?

  • 也许一些流行的第三方方法接受 EventHandler/EventHandler<T> 委托类型作为参数,因此如果我们的代码可能会使用这些第三方方法,我们应该使用预定义的委托类型 EventHandler/Eventhandler<T>

谢谢
5个回答

11

对我来说,这个问题有点奇怪。假如为某些TEventArgs定义与EventHandler<TEventArgs>完全匹配的委托类型,会有什么好处呢?

话虽如此,按照“正常”方式进行至少有一个好处:某些API已经期望使用EventHandler<TEventArgs>委托;例如,Rx Extensions包括一个看起来像这样的方法:

Observable.FromEvent<TEventArgs>(
    Action<EventHandler<TEventArgs>> addHandler,
    Action<EventHandler<TEventArgs>> removeHandler
);
如果您定义了自己的委托,使用像这样的方法 - 这些方法期望 EventHandler<TEventArgs> 委托 - 将变得比必要的复杂,而没有增加任何好处(至少我没有看到)。

7
您忘记了一个重要的事情:
  • 未来负责维护您代码的疯子会找到您的住所并加害于您。

5

你已经回答了自己的问题:

  • 语法糖(更少的代码)以保持惯例
  • 互操作性(使用EventHandler类型让您轻松集成来自其他库的事件

简而言之,除非被迫不得使用它(这通常是由于人们不知道它或不理解它的结果),否则没有不使用它的好理由。


3

我要提出一个完全异端的建议。我曾经坚定地站在EventArgs阵营,因为我坚持“微软推荐这样做,而且一直以来都是这样做”的思维方式,但随着时间的推移,我开始讨厌EventArgs了。为什么呢?

  • 它促进了一种依赖于弱类型/类型转换的.NET-1.0ish编码风格,让我感到不舒服。
  • 每次触发事件时,它会强制使实现事件的类使用新的EventArg实例污染堆,这也让我感到不安。为什么不让我的事件直接给订阅者他们需要的东西,而不是用一个对我无益的额外类包装它呢?
  • 订阅事件的回调方法的签名看起来像垃圾,几乎没有语义细节——例如object sender——发送者是什么?!?

现在我做的是声明自己的事件处理程序委托,在我的解决方案中整洁地存储在它们自己的“Delegates”文件夹和命名空间中。因此,我的委托可以像这样存在于它自己的文件中:

namespace MyAPI.Data.Delegates
{
    public delegate void DataEventHandler<TData>(DataFeed<TData> sender, TData data);
}

事件声明现在看起来是这样的:
public event DataEventHandler<TData> DataReady = delegate { };

采用这种方法的好处:

  • 方法签名具有更多的语义细节。你知道是发送了什么
  • 强类型是保留的。不再需要将object sender强制转换成你认为应该的类型。
  • 你不必new()实例化对象并污染堆,如果你的事件频繁发生,这可能会有问题。只需向你的订阅者传递他们所需的内容,无论是对象引用还是值类型。
  • 通过在委托中使用___EventHandler命名约定,你仍然在推广一种统一的代码风格,这使得你的API的用户容易知道你的意图。

唯一的 "缺点" 是它使得你的代码的用户很难将你的事件连接到已经存在的具有object sender, EventArgs e签名的方法。然而,这一点是无关紧要的,因为如果你的事件传递任何额外的数据(例如,你创建了自己的EventArgs子类),那么他们无论如何都必须改变方法签名(或将其转换为你的子类类型)。无论哪种方式,都很麻烦。

这就是我喜欢我的方式的原因。


3

来自《Pro C# 2008和.NET 3.5平台》

当编译器处理event关键字时,您将自动获得注册和取消注册方法*以及任何必要的成员变量**,以用于您的委托类型。...确保,event关键字只是语法糖,它只是为您节省了一些打字时间。

* 这包括重载方便的+=-=运算符。

** ...这些已经标记为private,因此它们无法绕过。

当您使用泛型EventHandler委托时,您甚至不需要完全编写自定义委托类型。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接