Event und Delegat Kontravarianz in .NET 4.0 und C# 4.0

Während der Untersuchung diese Frage ich habe neugierig, wie die neue Kovarianz/Kontravarianz features in C# 4.0 wird es betreffen.

In der Beta 1, C# scheint nicht einverstanden mit der CLR. Zurück in C# 3.0, wenn Sie hatte:

public event EventHandler<ClickEventArgs> Click;

... und dann anderswo, die Sie hatte:

button.Click += new EventHandler<EventArgs>(button_Click);

... würde der compiler barf, weil Sie nicht kompatibel sind Delegat-Typen. Aber in C# 4.0, kompiliert er fein, weil in CLR 4.0 der type-parameter ist nun markiert als in, also es ist kontravariant, und so geht der compiler davon aus der multicast-Delegat += arbeiten.

Hier mein 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");
    }
}

Aber auch wenn es kompiliert, es funktioniert nicht zur Laufzeit (ArgumentException: die Delegierten müssen vom gleichen Typ sein).

Es ist okay, wenn Sie nur fügen Sie entweder eine der beiden Delegaten-Typen. Aber die Kombination von zwei verschiedene Arten in einer multicast die Ausnahme verursacht, wenn der zweite Hinzugefügt.

Ich denke, das ist ein Fehler in der CLR in der beta 1 (die compiler-Verhalten sieht hoffentlich richtige).

Update für den Release Candidate:

Den oben genannten code nicht mehr kompiliert. Es muss sein, dass die Kontravarianz von TEventArgs im EventHandler<TEventArgs> delegieren, geben Sie Rollback ausgeführt worden, so dass nun Delegierte hat die gleiche definition wie in .NET 3.5.

Ist, die beta die ich angeschaut gehabt haben muss:

public delegate void EventHandler<in TEventArgs>(object sender, TEventArgs e);

Nun geht es zurück an:

public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);

Aber die Action<T> delegieren parameter T noch kontravariant:

public delegate void Action<in T>(T obj);

Das gleiche gilt für Func<T>'s T als kovariante.

Dieser Kompromiss macht sehr viel Sinn, solange wir davon ausgehen, dass die primäre Nutzung von multicast-Delegaten ist im Kontext der Ereignisse. Ich persönlich habe festgestellt, dass ich immer multicast-Delegaten, außer als Ereignisse.

Also ich denke mal C# coding standards können jetzt annehmen, eine neue Regel: keine form multicast-Delegaten, die von mehreren Delegierten Arten durch Kovarianz und Kontravarianz. Und wenn Sie nicht wissen, was das bedeutet, nur vermeiden Sie die Verwendung Action für die Ereignisse auf der sicheren Seite.

Natürlich, die Schlussfolgerung hat Konsequenzen für die ursprüngliche Frage, dass dies ein Zuwachs von...

  • Thoiugh interessant wollen ist die Frage?
  • Ich bin überrascht, dass dieses Loch entkommen die Ankündigung von C# - team, sollte eines der ersten Dinge, die Sie getestet haben würde, nach der Einführung Varianz generischer delegates, nicht wahr? C# 5 zeigen auch Sie (die clr-version, in der die gleichen).
Schreibe einen Kommentar