【问题标题】:Why *should* we use EventHandler为什么*应该*我们使用 EventHandler
【发布时间】:2011-04-22 07:13:52
【问题描述】:

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

我一直被告知EventHandler 是传统,等等等等。但我找不到为什么这个教条仍然存在的原因。

是否有理由让新的代表成为一个坏主意:

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

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

【问题讨论】:

标签: c# generics event-handling


【解决方案1】:

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

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

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

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

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

【讨论】:

  • +1 哇。好贴。这是让我回到 SO 的帖子类型。
  • 我不明白一件事。使用EventHandler 你不能使用YourEvent += EnvironmentExit,但是YourEvent += (sender, args) =&gt; Environment.Exit(-1) 怎么样?这不一样吗?Exit 将在完全信任的上下文中被调用?
  • 我想问同样的问题)我们可以简单地将 Enviroment.Exit(-1) 包装到 MyEventHandler..
  • @prostynick 评论是否使此回复无效?我们是不是又回到了原点——除了约定之外没有什么好的理由吗?
  • 这是错误的......正如@prostynick 所说,无论如何您都可以注册任何回调。为什么会有这么多赞?
【解决方案2】:

除了它是公认的 .net 约定之外,没有其他理由使用它,任何阅读您的代码的人都应该很容易理解它。为此,这是一个很好的理由。

但这是您的代码,您可以决定最适合您的代码。当然,当您与 fcl 交互时,您将不得不使用事件处理程序按照他们的方式进行操作。

【讨论】:

  • 话虽如此,强类型的委托也会被识别:)
  • 我不明白为什么开发人员会对 OP 的代码感到困惑。但是,+1 指出了显而易见的:这是他的代码,他可以随意处理。
【解决方案3】:

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

【讨论】:

    【解决方案4】:

    我同意你的观点,约定是愚蠢的和/或过时的。以正确的方式进行,具有适当的类型安全性和泛型。

    你总是有任务要做,你可以按照上一个人的方式去做,或者用你认为可能更好的另一种方式来做。

    通常会选择第一个选项——和最后一个人一样做,这样你就不会惹上麻烦。但第二个选择是长期改进软件的方法。 (或者至少它可以改进它,如果你是对的,你的方式更好!:))

    【讨论】:

      【解决方案5】:

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

      但是,通过在自定义 EventArgs 派生类中包含对发送者的类型安全引用,可以轻松解决您的问题。

      【讨论】:

      • 我不同意你的看法。例如,客户端代码在对象数组上只能有一个处理程序。
      【解决方案6】:

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

      使用EventHandler delegate 是这里介绍的指南: http://msdn.microsoft.com/en-us/library/ms229011.aspx

      【讨论】:

      • 不过,您可能会争辩说,如果使用 Action&lt;...&gt; 作为事件处理程序就足以让团队成员感到困惑,那么您的团队已经面临更大的问题了。 ;)
      • 我已经编程了 20 年,最近 10 年是在 C# 中,这会让我感到困惑,但是今天大多数高级商店的目标似乎是使用最复杂的设计,而不是使用简单的方法。
      • 自我发布该答案以来已经过去了 6 年,我完全坚持我的说法。周围有很多没有经验的开发人员,有些开发人员切换了语言,有些仍然是初级开发人员,但在项目中仍然需要他们等等,所以当你选择一个普通的开发人员时,你并不总是能得到最聪明的人地球上的人。当然,最好在一家只雇用奶油的公司工作,但实际上最好期待有人可能会对这样的事情感到困惑。即使是有经验的人也可能。最终目标应该是代码的就绪性。
      猜你喜欢
      • 2011-05-16
      • 1970-01-01
      • 2013-07-13
      • 2018-01-15
      • 1970-01-01
      • 2018-06-02
      • 2013-07-22
      • 2011-07-04
      • 2017-09-13
      相关资源
      最近更新 更多