5 Stimmen

Wenn ich für ein Ereignis in c# registrieren, während es versendet wird, bin ich garantiert nicht wieder während dieser Versendung aufgerufen werden?

In C#, finde ich mich gelegentlich wollen eine Methode für ein Ereignis in der Mitte einer Versendung von diesem gleichen Ereignis zu registrieren. Wenn ich z. B. eine Klasse habe, die Zustände auf der Grundlage von aufeinanderfolgenden Versendungen desselben Ereignisses umwandelt, möchte ich vielleicht, dass der Handler des ersten Zustands sich selbst abmeldet und den zweiten Handler registriert. Ich möchte jedoch nicht, dass der zweite Handler bis zum nächsten Auslösen des Ereignisses ausgelöst wird.

Die gute Nachricht ist, dass sich die Microsoft-Implementierung von C# anscheinend genau so verhält. Der Syntaxzucker für die Ereignisregistrierung wird durch einen Aufruf von System.Delegate.Combine ersetzt, der einfach die aktuelle Aufrufliste und die neue Methode in einer separaten Liste zusammenfasst und sie der Ereigniseigenschaft zuweist. Dadurch erhalte ich genau das Verhalten, das ich möchte.

Meine Frage ist also: Ist dieses Verhalten durch den Sprachstandard garantiert? Ich möchte in der Lage sein, meine C#-Code auf anderen Plattformen unter Mono laufen und in der Regel wollen sicherstellen, dass ich nicht machen Annahmen über den Sprachstandard auf der Grundlage seiner Implementierung.

Ich konnte auf MSDN keine definitiven Informationen finden.

Wenn Sie ein konkretes Beispiel dafür haben möchten, wovon ich spreche, hier ist ein Beispiel:

    delegate void TestDelegate();
    static event TestDelegate TestEvent;

    static void Main (string[] args) {
        TestEvent += TestDelegateInstanceFirst;
        TestEvent();
        TestEvent();
    }

    static void TestDelegateInstanceFirst () {
        Console.WriteLine("First");
        TestEvent += TestDelegateInstanceSecond;
    }

    static void TestDelegateInstanceSecond () {
        Console.WriteLine("Second");
    }

Zumindest unter Windows lautet die Ausgabe:

First
First
Second

9voto

Jon Skeet Punkte 1325502

Ja, das ist garantiert.

Aus der vereinheitlichten C# 3.0 Spezifikation, Abschnitt 15.1:

Wenn jedoch zwei Nicht-Null-Delegierte Instanzen kombiniert werden, werden ihre Aufruflisten konkateniert - in der in der Reihenfolge linker Operand dann rechter Operand, um eine neue Aufrufliste zu bilden, die zwei oder mehr Einträge enthält.

Beachten Sie die "neue Aufrufliste". Und wieder in Abschnitt 15.3:

Einmal instanziiert, delegieren Instanzen immer auf das gleiche Zielobjekt und Methode. Denken Sie daran, wenn zwei Delegaten kombiniert werden, oder ein Delegat von einem anderen entfernt wird, entsteht ein neuer Delegat mit seiner eigenen Aufrufliste entsteht; die Aufruflisten der Delegierten, die die kombiniert oder entfernt wurden, bleiben unverändert.

Schließlich heißt es in MSDN für System.Delegate:

Delegierte sind unveränderlich; einmal erstellt, die Aufrufliste eines Delegaten nicht mehr nicht ändern.

Ich vermute, dass es etwas in der CLI-Spezifikation gibt - ich werde es überprüfen, wenn Sie möchten, aber ich hoffe, diese drei haben Ihnen genug Vertrauen gegeben :)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X