Why events does not support binding inherited types?

In these delegates:

EventHandler

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

FormClosingEventHandler

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

FormClosingEventArgs is inherited from EventArgs . Why can't I bind an FormClosing event with an event handler from EventHandler delegate?

I know that the event handler's signiture must match its delegate, but why it doesn't suppot matching inherited types ?


Well, it's interesting...

You can bind an eventhandler using a method group conversion with compatible types:

public void GenericHandlerMethod(object sender, EventArgs e) {}

...
// Valid
foo.FormClosingEvent += GenericHandlerMethod;

This will actually create an instance of FormClosingEventHandler , not EventHandler .

However you can't subscribe directly with an existing delegate of type EventHandler:

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

... but you can create a new delegate based on an existing one, if the types are compatible:

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

Basically you need to remember that all the syntactic sugar is effectively calling a method like this:

foo.AddFormClosingHandler(handler);

where the method has a signature of:

public void AddFormClosingHandler(FormClosingHandler handler)

Now remember that although they have compatible signatures, there's no reference conversion available from EventHandler to FormClosingHandler . It's not like one inherits from the other.

It gets even more confusing with generic covariance/contravariance, but we'll leave it there for now... hopefully that's given you something to chew on and options for working round the restrictions.


A delegate which points directly to an object method holds three pieces of information:

  • The target object upon which the method should act, or `null` in the case of static methods
  • A reference to a function which acts upon that type of object, or a static function if the target is `null`.
  • The type of the delegate itself.

    A delegate which is produced by using Delegate.Combine to combine a total of N single-cast delegates will contain N targets, N methods, and ONE delegate type. Given the (IMHO rather icky and unfortunate) way in which Delegate.Combine and Delegate.Remove are used, there's no way the system could allow existing uses of Combine to accept delegates of different types.

    For example, a routine might need an EventHandler<IFoo> . If classes Moe and Larry both implement IFoo and IBar , such a routine should be able to accept an EventHandler<Moe> or an EventHandler<Larry> . If each delegate type had its own definition for Combine , it might be possible to feed EventHandler<IFoo>.Combine() a delegate of type EventHandler<Moe> and one of EventHandler<Larry> , and have it generate a combined delegate handler of type EventHandler<IFoo> . Unfortunately, there's one Delegate.Combine() method for all delegate types, and there's no way that it can look at an EventHandler<Moe> and an EventHandler<Larry> and figure out what type the combined delegate should be (even if Delegate.Combine had the ability to identify types to which both event handlers could be cast, it would have no way of knowing whether to use EventHandler<IFoo> or EventHandler<IBar> ).

    链接地址: http://www.djcxy.com/p/35700.html

    上一篇: 调用另一个类的定时器事件

    下一篇: 为什么事件不支持绑定继承类型?