在这些代表中:
EventHandler
public delegate void EventHandler(object sender,EventArgs e);
FormClosingEventHandler
public delegate void FormClosingEventHandler(object sender,FormClosingEventArgs e);
FormClosingEventArgs
继承自EventArgs
。为什么我无法使用FormClosing
委托的事件处理程序绑定EventHandler
事件?
我知道事件处理程序的签名必须与其委托匹配,但为什么它不支持匹配继承的类型?
答案 0 :(得分:2)
嗯,这很有意思......
您可以使用兼容类型的方法组转换绑定事件处理程序:
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
没有可用的参考转换。它不像是从另一个继承而来。
通用协方差/逆变会让它变得更加混乱,但我们暂时将它留在那里......希望能给你一些可以咀嚼的东西以及解决这些限制的选择。
答案 1 :(得分:1)
直接指向对象方法的委托包含三条信息:
通过使用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>
)。