代码之家  ›  专栏  ›  技术社区  ›  Daniel Earwicker

如果在中放弃标准的EventHandler模式,我会失去什么。网?

  •  22
  • Daniel Earwicker  · 技术社区  · 16 年前

    delegate 类型,它接受一个名为sender的普通对象,然后在第二个参数中接受实际的“有效载荷”,该参数应从 EventArgs .

    第二个参数的基本原理来自 看起来很清楚(见 .NET Framework Standard Library Annotated Reference ).它旨在确保随着软件的发展,事件接收器和源之间的二进制兼容性。对于每个事件,即使它只有一个参数,我们也会派生一个自定义的事件参数类,该类有一个包含该参数的属性,这样我们就可以在未来的版本中保留向有效载荷添加更多属性的能力,而不会破坏现有的客户端代码。在独立开发组件的生态系统中非常重要。

    但我发现,零争论也是如此。这意味着,如果我在第一个版本中有一个没有参数的事件,我会写:

    public event EventHandler Click;
    

    …那我做错了。如果我将来将委托类型更改为新类作为其有效载荷:

    public class ClickEventArgs : EventArgs { ...
    

    add_Click 这需要 EventHandler ,如果我更改委托类型,他们就找不到重载,所以有一个 MissingMethodException .

    好吧,那么如果我使用方便的通用版本呢?

    public EventHandler<EventArgs> Click;
    

    不,还是错了,因为 EventHandler<ClickEventArgs> EventHandler<EventArgs> .

    事件参数 ,你

    然后是第一个论点, sender 在我看来,这就像是邪恶结合的秘诀。事件触发本质上是一个函数调用。一般来说,函数是否应该能够深入堆栈,找出调用者是谁,并相应地调整其行为?我们是否应该强制界面看起来像这样?

    public interface IFoo
    {
        void Bar(object caller, int actualArg1, ...);
    }
    

    毕竟,实施者 Bar 可能想知道谁 caller 是,所以他们可以查询更多信息!我希望你现在已经吐了。为什么事件会有所不同?

    事件参数 -我声明的每个事件的派生类,只是为了让它值得我使用 事件参数

    Visual Studio的自动补全功能似乎并不关心你在事件中使用什么委托——你可以键入 += 它为您编写了一个处理程序方法,该方法与它碰巧是什么委托相匹配。

    作为一个额外的问题,C#/CLR 4.0会做任何事情来改变这一点吗,也许是通过委托中的逆变?我试图调查这件事,但打了 another problem 。我原本将这方面的问题纳入另一个问题中,但这引起了混淆。把这个问题分成三个问题似乎有点过分。..

    更新:

    事实证明,我想知道逆变对整个问题的影响是正确的!

    作为 noted elsewhere EventHandler<T> 不同于 Action<T> .

    EventHandler<TEventArgs> ;这只是意味着,如果你使用通用委托类型,不要选择启用了逆变的委托类型。

    2 回复  |  直到 16 年前
        1
  •  7
  •   George Stocker NotMe    15 年前

    没什么,你什么也没失去。我一直在使用 Action<> 因为。NET 3.5问世了,它更自然,更容易编程。

    EventHandler 对于生成的事件处理程序,只需编写所需的方法签名并将其与lambda连接起来:

    btnCompleteOrder.OnClick += (o,e) => _presenter.CompleteOrder();
    
        2
  •  2
  •   supercat    15 年前

    我也不喜欢事件处理程序模式。在我看来,Sender对象并没有那么有帮助。如果某个事件表示某个对象发生了某些事情(例如更改通知),那么将信息放在nvarchar中会更有帮助。我能为Sender找到的唯一用途是取消订阅某个事件,但并不总是清楚应该取消订阅哪个事件。

    顺便说一句,如果我有其他选择,Event就不会是AddHandler方法和RemoveHandler方法;它只是一个AddHandler方法,它将返回一个可用于取消订阅的MethodInvoker。我希望第一个参数是取消订阅所需的MethodInvoker的副本,而不是Sender参数(以防对象发现自己正在接收取消订阅调用者丢失的事件)。标准的MulticastDelegate不适合分派事件(因为每个订阅者都应该收到不同的取消订阅委托),但取消订阅事件不需要在调用列表中进行线性搜索。