【问题标题】:Event parameter; "sender as Object", or "sender as T"?事件参数; “作为对象的发件人”,还是“作为 T 的发件人”?
【发布时间】:2011-02-09 12:09:06
【问题描述】:

当我为我的业务对象编写公共事件时,除了附加特定参数之外,我已经习惯了始终将实例作为“sender as Object”传递的习惯。我现在才问自己为什么我不指定类

所以对于有更多经验的你来说; 您是否曾在事件中将不同的类作为发送者传递?如果是这样,您的决策标准是什么时候可以/不可以?

【问题讨论】:

  • 如果你不得不问“我为什么不”,你真的不应该这样做。关于如何创建事件签名的指南的设计是有原因的。至少在决定偏离它们之前阅读这些原因,因为你可以。
  • 想一想:如果稍后您认为您的事件适合其他地方,并且您想从代码中的另一个点提出它怎么办。它会是同一个发件人类吗?如果您指定发件人的类型,则不会...
  • @Lasse:我也可以问“我为什么要这样做?”。我不知道这是一个指导方针,我不是专业程序员。仍然有一个准则,我想知道违反该准则是否常见或非常罕见。
  • @Felipe:我从来没有在不同的发送者类之间共享一个事件。但也许这是我可以学习并从中受益的做法。

标签: c# .net vb.net oop events


【解决方案1】:

不要太极端。 EventHandler(object sender, EventArgs e) 有一个对象发送者,因此我们可以在许多情况下使用它。但这并不意味着强类型的发件人是邪恶的。当这个委托不会被广泛使用时(例如EventHandler),强类型的发送者很有用,例如

public delegate void SaveHandler(Controller sender, EventArgs e);

现在其他开发人员(或使用您的库的人)可以识别发件人必须Controller,他们会很高兴不要这样编码:

public void MySaveHandler(object sender, EventArgs arg)
{
   var controller = sender as Controller;
   if (controller != null)
   {
       //do something
   }
   else
   {
       //throw an exception at runtime? 
       //It can be avoided if sender is strongly-typed
   }
}

你甚至可以让它通用:

public delegate void SaveHandler<T>(T sender, EventArgs args) 
                                              where T: IController;

在 C# 中这是纯粹的合法和良好实践。你应该明确你想做什么,然后选择更好的方法。它们中的任何一个都是邪恶的/坏的。

【讨论】:

    【解决方案2】:

    有一个design guideline 指定事件处理程序应该有两个参数:sender(一个对象)和 e(EventArgs 或派生自那个)。

    【讨论】:

    • +1:我个人认为这里是最好的建议。指导方针不是规则或法律。你可以偏离它们,但在你这样做之前,你真的应该知道为什么它们首先被创建,它们试图管理什么样的问题或情况,以及你的替代方案是什么。仅仅因为你可以而偏离从来都不是一个好的理由。
    • @Lasse:实际上,我怀疑他们选择这个有一个有效的(或者至少“足够好”)的理由,除了 .NET 的第一个版本中没有泛型。跨度>
    • @Groo:我似乎记得不久前在一个 MSDN 博客上读到过,这正是设计决定将 sender 参数类型为对象的原因。只是其中之一现在已经成为人们期望在公共 API 中如此完善的约定。如果参数没有公开公开,那么绝对没有理由不应该强烈或一般地输入参数。
    【解决方案3】:

    没有这样的限制。这只是整个 BCL(基类库)和其他流行框架都遵循的准则。

    如果它将被其他开发人员使用或作为框架发布,我建议您遵循它以保持一致。

    【讨论】:

      【解决方案4】:

      据我所知,您可以使用所需参数创建委托,然后使用该委托创建事件,然后您可以调用该事件并传入参数,或者您可以使用自定义事件参数,如 @987654321 所示@。正如另一个答案所暗示的那样。保持一致。

      并未真正回答您关于决策标准的问题,但希望对您有所帮助

      【讨论】:

        【解决方案5】:

        我目前的理念是使代码实践尽可能接近标准的 Microsoft 方式。你从中得到两件事:

        • 新开发人员可以快速理解您的代码
        • 您培训现有开发人员如何使用框架的其余部分

        【讨论】:

          【解决方案6】:

          最好使用object sender, EventArgs e 签名,因为该方法可以处理该签名的任何 事件。例如,在使用图表控件的项目中,有几种类型的 MouseOver 事件 - 来自 DataSeries、来自图例、来自整个 Canvas。

          这样,您可以处理任何事件源,因为大多数情况下,信息位于EventArgs

          此外,您不必在将发送者传递给委托时强制转换它,因为任何类实例都是一个对象。

          【讨论】:

          • 我认为这无关紧要。客户端代码仍然可以通过发送者类型为object 的方法来处理事件,即使事件是使用更强类型的发送者声明的。 Contravariance.
          【解决方案7】:

          前段时间在 StackOverflow 上有很多关于相关问题的讨论。这是那个问题:Event Signature in .NET -- Using a strong-typed sender

          最终,归结为偏好。在大多数情况下,您希望您的事件处理程序绑定到特定类型的类,因此使发送者成为一个对象,然后强制转换回该类以访问其属性可能不适合您 [它也不适合我]。

          此外,随着 .NET 3+ 和委托协变和逆变的引入,使用强类型委托应该不成问题。我必须承认,我在代码中不止一次使用了强类型事件处理程序。

          就像我之前说的,这取决于偏好;微软刚刚发布了一套指南行而不是规则...

          【讨论】:

            【解决方案8】:

            拥有这样的实现对您没有约束力。它通常是因为EventHandler delegate 是用这样的原型设计的。

            它是一个simple guideline,后跟基类库。但请确保您可以创建自己的参数和实现。

            但请记住,如果它是由您以外的其他开发人员使用的,他将需要了解此类实现。它的目的是为了更好地和灵活地在任何地方使用事件,而不管它使用的类。

            如果您为事件定义 Custom Prototype,那么我建议您也定义 Custom Delegate 以确保您能够捕获 exception > 如果没有通过正确的类型。 (如果需要,用户需要进行显式转换)

            像这样:

            public delegate void MyEventHandler( MyType sender, EventArgs e);
            

            然后在需要的地方使用它:

            this.MyEvent += new MyEventHandler(my_eventhandlerfunction);
            

            【讨论】:

              猜你喜欢
              • 2013-11-03
              • 2014-06-03
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-10-24
              • 2020-12-19
              • 2020-12-22
              • 2019-05-24
              相关资源
              最近更新 更多