【问题标题】:Is the "sender" in Button_Click(object sender... really the sender?Button_Click(object sender... 中的“发件人”真的是发件人吗?
【发布时间】:2010-10-14 04:55:42
【问题描述】:

Ted Faison 在podcast on event-based software design 中提到 .NET、C++ 和 Java 事件语句中的“sender”和“self”对象,例如:

private void Button_Click(object sender, RoutedEventArgs e)

是用词不当,因为例如在上面的例子中,“sender”并不是真正产生事件的对象,而是一个代理,因为你不想把你的应用程序耦合得那么紧密。

我是不是理解错了(因为我调试的时候,“sender”确实是原来的对象)。

或者这些语言中的常见事件模式(例如常见的点击处理程序)是紧密耦合的,但它们应该更加解耦,例如在复合应用中。

他还提到过,例如你不应该从 EventArgs 继承,因为它会导致类爆炸,每个事件一个,它只传输几个变量。在他看来,很多时候,你可以发送一个字符串。他提到,这种观点与微软模式和实践所建议的相反。

对这些领域有什么想法吗?

【问题讨论】:

  • +1。好问题。自从我听到那个播客后,我一直在考虑根据我正在开发的系统的总体架构来制作事件。
  • Ted Faison 的《基于事件的编程:将事件发挥到极致》一书可通过books.google.com/…在线获取
  • 关于最后一个问题:Ted Faison 大约在 podcat 中谈到了这个问题。 29 分 30 秒,大约35 分钟。

标签: c# event-driven-design


【解决方案1】:

在大多数情况下,sender 引发事件的Button(或其他)。在某些情况下,不是,例如(可能是懒惰的)pass-thru 事件:

class Foo {
   private Bar bar;
   public Foo(Bar bar) {
       this.bar = bar;
   }
   public event EventHandler SomeEvent {
       add {bar.SomeEvent += value;}
       remove {bar.SomeEvent -= value;}
   }
   //...
}

在这里,如果我们订阅 foo.SomeEvent,我们实际上会取回由 Bar 实例发起的事件 - 所以 sender 不会foo。但这可以说是因为我们错误地实现了Foo.SomeEvent

说实话,大多数情况下你不需要检查sender;这很有用的主要时间是当许多控件共享一个处理程序时。您通常应该能够假设发件人是您订阅的实例(出于引用相等测试的目的)。

Re EventArgs - 标准模式(在创建新的事件类型时)建议您继承此模式。我不建议偏离这一点。一个次要原因是它允许您使用EventHandler<T>,但也有其他差异原因。此外——有时做别人期望的事情就足够了;人们期望一个EventArgs派生值。

也就是说 - 我之前做过非标准事件(在 MiscUtil 的 Push LINQ 中) - 但这已经是一个非常不寻常的设置,所以它并不觉得不合适。

【讨论】:

    【解决方案2】:

    首先 - 'sender' 将保存对您单击的按钮的引用。如果您有多个按钮都连接到同一个事件,这就是您查看您点击了哪个按钮的方式(如果您没有在事件参数中传递某些内容来读取此内容)。

    另外,我在某种程度上同意编写继承 frmo EventArgs 的新 eventargs 会导致类爆炸——因此请谨慎使用。我喜欢只引发一个 EventArgs.Empty,然后让代码捕获事件显式查询引发数据事件的对象。我的意思是 - 一旦你捕捉到事件,而不是从事件参数中读取数据,而是转到引发事件的对象并读取你感兴趣的属性。这使得阅读你需要的内容变得更容易,但当然 - 您可能会发现自己处于这些属性在引发事件和读取属性之间发生变化的情况。

    【讨论】:

      猜你喜欢
      • 2011-04-07
      • 1970-01-01
      • 2013-11-03
      • 2012-12-24
      • 2015-01-13
      • 1970-01-01
      • 2012-03-30
      • 2023-03-26
      • 2013-05-29
      相关资源
      最近更新 更多