【问题标题】:Why events does not support binding inherited types?为什么事件不支持绑定继承类型?
【发布时间】:2011-07-21 12:19:57
【问题描述】:

在这些代表中:

EventHandler

public delegate void EventHandler(object sender, EventArgs e);

FormClosingEventHandler

public delegate void FormClosingEventHandler(object sender, FormClosingEventArgs e);

FormClosingEventArgs 继承自 EventArgs。为什么我不能将 FormClosing 事件与来自 EventHandler 委托的事件处理程序绑定?

我知道事件处理程序的签名必须与其委托匹配,但为什么它不支持匹配继承的类型?

【问题讨论】:

    标签: c# events delegates event-handling


    【解决方案1】:

    嗯,这很有趣……

    可以使用兼容类型的方法组转换绑定事件处理程序:

    public void GenericHandlerMethod(object sender, EventArgs e) {}
    
    ...
    // Valid
    foo.FormClosingEvent += GenericHandlerMethod;
    

    这实际上会创建一个FormClosingEventHandler 的实例,不是 EventHandler

    但是您不能直接使用 EventHandler 类型的现有委托进行订阅:

    EventHandler genericHandler = GenericHandlerMethod;
    // Invalid
    foo.FormClosingEvent += genericHandler;
    

    ...但如果类型兼容,您可以基于现有委托创建新委托:

    EventHandler generic = GenericHandlerMethod;
    FormClosingEventHandler closingHandler = new FormClosingEventHandler(generic);
    // Valid
    foo.FormClosingEvent += closingHandler;
    

    基本上你需要记住,所有的语法糖都是有效地调用这样的方法:

    foo.AddFormClosingHandler(handler);
    

    方法的签名为:

    public void AddFormClosingHandler(FormClosingHandler handler)
    

    现在请记住,尽管它们具有兼容的签名,但没有从 EventHandlerFormClosingHandler 的参考转换可用。这不像是一个继承另一个。

    它与泛型协变/逆变更加混淆,但我们暂时将其留在那里......希望这能给你一些东西来咀嚼和解决这些限制的选项。

    【讨论】:

    • 非常好的答案,谢谢。唯一的问题是在 UI 中生成事件处理程序的 IDE 不支持这样的工作。所以我必须手动绑定它们。为此我问逻辑上为什么它不支持。
    • @John:呸,当涉及到事件处理程序时,我讨厌 Visual Studio。希望答案能解释为什么在实际代码中存在限制 - VS 限制超出了我的理解;)
    【解决方案2】:

    直接指向对象方法的委托包含三个信息:

    1. 方法应作用的目标对象,或者在静态方法的情况下为“null”
    2. 对作用于该类型对象的函数的引用,如果目标为“null”,则为静态函数。
    3. 委托本身的类型。

    通过使用Delegate.Combine 组合总共 N 个单播委托生成的委托将包含 N 个目标,N方法和 ONE 委托类型。鉴于 Delegate.CombineDelegate.Remove 的使用方式(恕我直言,相当恶心和不幸),系统不可能允许现有的 Combine 使用接受不同类型的代表。

    例如,例程可能需要EventHandler<IFoo>。如果类MoeLarry 都实现IFooIBar,那么这样的例程应该能够接受EventHandler<Moe>EventHandler<Larry>。如果每个委托类型都有自己的Combine 定义,则可以为EventHandler<IFoo>.Combine() 提供EventHandler<Moe> 类型的委托和EventHandler<Larry> 之一,并让它生成EventHandler<IFoo> 类型的组合委托处理程序。不幸的是,所有委托类型都有一个 Delegate.Combine() 方法,它无法查看 EventHandler<Moe>EventHandler<Larry> 并确定组合委托应该是什么类型(即使 Delegate.Combine 有能力要识别两个事件处理程序都可以转换为的类型,它无法知道是使用EventHandler<IFoo> 还是EventHandler<IBar>)。

    【讨论】:

      猜你喜欢
      • 2010-11-16
      • 2013-07-01
      • 1970-01-01
      • 2011-04-15
      • 2016-04-18
      • 2014-03-04
      • 2011-03-17
      • 2011-02-21
      相关资源
      最近更新 更多