为什么事件不支持绑定继承类型?

时间:2011-03-23 17:16:28

标签: c# events delegates event-handling

在这些代表中:

EventHandler

  

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

FormClosingEventHandler

  

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

FormClosingEventArgs继承自EventArgs。为什么我无法使用FormClosing委托的事件处理程序绑定EventHandler事件?

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

2 个答案:

答案 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)

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

通用协方差/逆变会让它变得更加混乱,但我们暂时将它留在那里......希望能给你一些可以咀嚼的东西以及解决这些限制的选择。

答案 1 :(得分:1)

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

  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>)。