Studying this issue , I became interested in how this will affect the new possibilities of covariance / contravariance in C # 4.0.
In beta 1, C # does not seem to agree with the CLR. Return to C # 3.0 if you have:
public event EventHandler<ClickEventArgs> Click;
... and then in another place:
button.Click += new EventHandler<EventArgs>(button_Click);
... the compiler will be barf, because these are incompatible delegate types. But in C # 4.0, it compiles fine, because in CLR 4.0 the type parameter is now marked as in , therefore it is contravariant, and therefore the compiler assumes that the multicast delegate += will work.
Here is my test:
public class ClickEventArgs : EventArgs { } public class Button { public event EventHandler<ClickEventArgs> Click; public void MouseDown() { Click(this, new ClickEventArgs()); } } class Program { static void Main(string[] args) { Button button = new Button(); button.Click += new EventHandler<ClickEventArgs>(button_Click); button.Click += new EventHandler<EventArgs>(button_Click); button.MouseDown(); } static void button_Click(object s, EventArgs e) { Console.WriteLine("Button was clicked"); } }
But although it compiles, it does not work at runtime ( ArgumentException : delegates must be of the same type).
This is fine if you add only one of the two types of delegates. But a combination of two different types in multicast throws an exception when a second is added.
I assume this is a bug in the CLR in beta 1 (the compiler behavior looks, hopefully, correct).
Update for Release Candidate:
The above code no longer compiles. It must be that TEventArgs comparability in the EventHandler<TEventArgs> delegate type is rollback, so now the delegate has the same definition as in .NET 3.5.
That is, the beta I was looking at should have:
public delegate void EventHandler<in TEventArgs>(object sender, TEventArgs e);
Now it goes back to:
public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);
But the delegate parameter Action<T> T is still contravariant:
public delegate void Action<in T>(T obj);
The same can be said for Func<T> T being covariant.
This trade-off makes a lot of sense if we assume that the initial use of multicast delegates is in the context of events. I personally found that I never use multicast delegates other than events.
So, I believe that C # coding standards can now accept a new rule: do not form multicast delegates from several types of delegates related to covariance / contravariance. And if you don't know what that means, just avoid using Action for events that are on the safe side.
Of course, this conclusion matters to the original question that this sprout grew from ...