为啥事件不支持绑定继承类型?
Posted
技术标签:
【中文标题】为啥事件不支持绑定继承类型?【英文标题】: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
委托的事件处理程序绑定?
我知道事件处理程序的签名必须与其委托匹配,但为什么它不支持匹配继承的类型?
【问题讨论】:
【参考方案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)
现在请记住,尽管它们具有兼容的签名,但没有从 EventHandler
到 FormClosingHandler
的参考转换可用。这不像是一个继承另一个。
它与泛型协变/逆变更加混淆,但我们暂时将其留在那里......希望这能给你一些东西来咀嚼和解决这些限制的选项。
【讨论】:
非常好的答案,谢谢。唯一的问题是在 UI 中生成事件处理程序的 IDE 不支持这样的工作。所以我必须手动绑定它们。为此我问逻辑上为什么它不支持。 @John:呸,当涉及到事件处理程序时,我讨厌 Visual Studio。希望答案能解释为什么在实际代码中存在限制 - VS 限制超出了我的理解;)【参考方案2】:直接指向对象方法的委托包含三个信息:
-
方法应作用的目标对象,或者在静态方法的情况下为“null”
对作用于该类型对象的函数的引用,如果目标为“null”,则为静态函数。
委托本身的类型。
通过使用Delegate.Combine
组合总共 N 个单播委托生成的委托将包含 N 个目标,N方法和 ONE 委托类型。鉴于 Delegate.Combine
和 Delegate.Remove
的使用方式(恕我直言,相当恶心和不幸),系统不可能允许现有的 Combine
使用接受不同类型的代表。
例如,例程可能需要EventHandler<IFoo>
。如果类Moe
和Larry
都实现IFoo
和IBar
,那么这样的例程应该能够接受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>
)。
【讨论】:
以上是关于为啥事件不支持绑定继承类型?的主要内容,如果未能解决你的问题,请参考以下文章