.NET事件的签名

4

可能是重复的问题:
C#中为什么事件需要(sender, EventArgs)?

我刚在一个项目上运行了VS2012代码分析工具,并发现它抱怨这段代码:

public delegate void PerMbHandler(long totalMb);

public event PerMbHandler NotifyMegabyteIncrement;

CA1009声明'MyWebClient.PerMbHandler'的第二个参数为EventArgs类型或命名为'e'的扩展EventArgs类型的实例。

MSDN解释:

事件处理程序方法需要两个参数。第一个参数是类型为System.Object且命名为'sender'的对象,这是引发事件的对象。第二个参数是类型为System.EventArgs且命名为'e'的数据,它与事件相关联。例如,如果事件在每次打开文件时触发,则事件数据通常包含文件的名称。

MSDN简单说明了惯例,而不是存在的原因。

使用长参数而不是 EventArgs 的子类会出现什么问题?这是约定和程序员期望的问题,还是必须遵循该模式的一些微妙技术原因?我说微妙,因为代码似乎工作得很好。

我认为这不是它不能工作的问题,而是违反了事件处理程序的约定。我认为大多数开发人员都希望事件处理程序具有MSDN中描述的形式,并且会对您的委托表示怀疑 - 特别是如果他们期望在引发事件时能够获取发送方的引用,但事件的处理程序不支持提供它的签名。 - David W
@DavidW:你说的很有可能是对的,这也是我的第一反应。我会很感兴趣地看看是否存在一些边缘情况,真的会导致事情出错。 - Eric J.
2个回答

5

使用长参数而不是EventArgs的子类会有什么问题?

事件参数
这本身并没有错,但它不够可扩展。举个例子,在六个月后,您可能需要传递两个long类型的参数,或者添加一个字符串,或者添加一整个列表的信息。在方法签名中使用 EventArgs ,您可以传递任何派生类型而不会破坏现有的消费者; 使用特定值类型,则受到非常大的限制。

EventArgs 还允许您与引发事件的类进行通信,例如 CancelEventArgs

发送方
老实说,我很少使用发送方。它也有些模糊不清。例如,控件上的自定义事件由文本框输入触发...发送方是谁?文本框(可能更有用),还是声明自定义事件的控件?

尽管如此,它是一个熟悉的约定,并且通过良好记录的接口,它可以很有用。


2
当您需要将相同的事件处理程序代码附加到许多不同的项目时,发送者非常有用。 - Joel Coehoorn
这是一个很好的例子,我想这就是我的答案的重点:(sender, args) 签名支持各种可能性,即使你今天用不到它们也没关系。 - Tim M.
只是确认一下。你真的不能将子类传递给委托吗?这不违反了多态性吗?背后的逻辑是什么? - TimFoolery
不,您可以将子类传递给委托。我写这篇文章已经有一段时间了,但我相信我的观点是,如果事件签名只采用原始类型(参见OP),则如果您想在将来传递其他值,则会受到限制。通过传递EventArgs(或其子类),即使输入数据发生更改,也可以保留签名。 - Tim M.
那么,如果您要添加其他参数,这样可以避免更改所有目标函数签名吗?这是唯一的优点吗? - TimFoolery
那,以及所有事件签名的一致性。 - Tim M.

2

没有什么会出错,事件和事件处理程序签名都经过了强类型检查。所有消息所做的只是警告您另一个使用您的事件的程序员会感到困惑,为什么事件具有如此不寻常的签名。 减速带会产生错误,这种错误是由程序员坚持需要获取发送方而产生的。

请记住 FxCop(也称“代码分析”)试图做什么。它不检查错误,这是编译器的工作。它存在的目的是让您知道您可能没有考虑到的事情。它有时可能会有点唠叨,特别是当它在 CAS 上面玩弄或不适当地标记臭名昭著的 CA2000 时。但这肯定是一个好的警告,您没有考虑到它。


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