It's possible for a generic delegate declaration to specify that certain type parameters should be covariant or contravariant, which would allow the types of assignments you're after. Unfortunately, the internal implementation of multicast delegates makes it impossible to combine delegates of different types (a "simple" delegate holds information about its type, along with a method pointer and a reference to its target; a multicast delegate information about its type along with holds the method pointers and target references for each of its constituent delegates, but does not hold any reference to the original delegates that were combined, nor does it hold any information about their types). An attempt to combine an EventHandler<DerivedEventArgs>
with an EventHandler<EventArgs>
will thus fail at run-time.
If EventHandler<T>
were contravariant with respect to T
, an attempt to pass an EventHandler<EventArgs>
to a standard event AddHandler
method which expects an EventHandler<DerivedEventArgs>
would compile, and would even succeed if no other handlers were subscribed, since the EventHandler<EventArgs>
would be Delegate.Combine
d with null
, thus being stored in the event's delegate field as an EventHandler<EventArgs>
. Unfortunately, a subsequent attempt to add anEventHandler<DerivedEventArgs>
(which is actually the expected type) would fail since its type doesn't match the delegate it's being combined with. Microsoft decided this behavior would violate the Principle of Least Astonishment (if passing the "wrong" delegate will cause any problem, it should do so when that delegate is passed, rather than when a later one is passed), and decided to minimize the likelihood of the scenario by making it so that an attempt to pass an EventHandler<EventArgs>
to a handler that expects an EventHandler<DerivedEventArgs>
will fail compilation, even though the act could succeed if it was the only subscription.