为什么*应该*我们使用EventHandler

时间:2010-10-07 10:37:01

标签: c# generics event-handling

我讨厌EventHandler。如果我想对它做任何事情,我讨厌我必须施放sender。我讨厌我必须创建一个继承自EventArgs的新类来使用EventHandler<T>

我一直被告知EventHandler是传统而且是等等,等等......无论如何。但我找不到这个教条仍然存在的原因。

为什么建立新代表是个坏主意:

delegate void EventHandler<TSender, T>(TSender sender, T args);

那样sender将是类型安全的,我可以传递我想要的任何东西作为参数(如果我愿意的话,包括自定义EventArgs)。

6 个答案:

答案 0 :(得分:24)

如果您完全信任的代码将第三方代码托管为部分信任,则实际上有充分理由要求第二个参数派生自EventArgs

因为事件处理委托的回调是在引发代码而不是第三方代码的上下文中完成的,所以恶意第三方代码可能会将特权系统操作添加为事件处理程序,从而可能执行通过在完全可信的上下文中运行代码来升级特权攻击,使其部分受信任的上下文无法运行。

例如,如果您将处理程序声明为int -> void类型,那么第三方代码可能会将YourEvent += Enviroment.Exit(-1)排入队列并让您无意中退出该进程。这显然会导致一个易于检测的问题,但是有更多的恶意API可以排队做其他事情。

当签名为(object, EventArgs) -> void时,框架中没有可以排队的特权操作,因为它们都不与此签名兼容。这是框架中安全代码审查的一部分,以确保这一点(遗憾的是,我找不到我读到这里的来源)。

因此,在某些情况下,为什么要使用标准模式存在有效的安全问题。如果您100%确定您的代码永远不会在这些情况下使用,那么事件签名指南并不重要(除了其他开发人员认为WTF之外),但如果可能的话,那么您应该遵循它。

答案 1 :(得分:9)

没有理由使用其接受的.net约定以外的其他人,阅读代码的任何人都应该很容易理解它。对此,这是一个很好的理由。

然而,这是你的代码,你可以决定最适合你的。当然,当您与fcl交互时,您将不得不使用事件处理程序。

答案 2 :(得分:6)

我通常使用Action<...>类型作为事件处理程序 - 如果您不需要与特别需要EventHandler的其他代码(或设计器)互操作,则没有理由使用它。

答案 3 :(得分:2)

好吧,完成所有这些转换是不寻常的,客户端代码通常已经知道 sender 是谁,因为它只显示了一个对象的事件。共享事件处理程序是相当罕见的。如果需要通用行为,那么更好的方法是从类派生并覆盖OnXxxx方法。然后你不再关心发件人了,你有这个

但是,通过在自定义EventArgs派生类中包含对发件人的类型安全引用来解决您的问题。

答案 4 :(得分:2)

我同意你的看法,这个惯例是愚蠢的和/或过时的。以正确的方式进行,具有适当的类型安全性和通用性。

它总是在你有任务要做的时候出现,你可以按照最后一个人的方式去做,或者以你认为可能更好的另一种方式做。

通常选择第一个选择 - 与最后一个人一样,你不会遇到麻烦。但第二个选择是长期改进软件。 (或者至少它可以改善它,如果你的方式更好!:))

答案 5 :(得分:0)

正如Preet Sangha所说,创建这样一个委托的原因是一个坏主意是其他开发人员可能会因为这样做而感到困惑。

使用EventHandler委托是此处提供的指南: http://msdn.microsoft.com/en-us/library/ms229011.aspx