it-swarm.com.de

So entfernen Sie einen Lambda-Ereignishandler

Mögliche Duplikate:
Abbestellen der anonymen Methode in C #
Wie hebe ich die Registrierung eines anonymen Ereignishandlers auf

Ich habe kürzlich entdeckt, dass ich mit Lambdas einfache Event-Handler erstellen kann. Ich könnte zum Beispiel ein Klickereignis wie das folgende abonnieren:

button.Click += (s, e) => MessageBox.Show("Woho");

Aber wie würden Sie es abbestellen?

220
Svish

In der C # -Spezifikation wird explizit angegeben (IIRC), dass bei Verwendung von zwei anonymen Funktionen (anonyme Methoden oder Lambda-Ausdrücke) möglicherweise gleiche Delegaten aus diesem Code erstellt werden oder nicht. (Zwei Delegierte sind gleich, wenn sie gleiche Ziele haben und auf die gleichen Methoden verweisen.)

Um sicherzugehen, müssen Sie sich an die von Ihnen verwendete Delegateninstanz erinnern:

EventHandler handler = (s, e) => MessageBox.Show("Woho");

button.Click += handler;
...
button.Click -= handler;

(Ich kann das relevante Bit der Spezifikation nicht finden, aber ich wäre ziemlich überrascht, wenn der C # -Compiler aggressiv versuchen würde, gleiche Delegaten zu erstellen. Es wäre sicherlich unklug, sich darauf zu verlassen.)

Wenn Sie das nicht möchten, müssen Sie eine Methode extrahieren:

public void ShowWoho(object sender, EventArgs e)
{
     MessageBox.Show("Woho");
}

...

button.Click += ShowWoho;
...
button.Click -= ShowWoho;

Wenn Sie eine Ereignisbehandlungsroutine erstellen möchten, die sich mithilfe eines Lambda-Ausdrucks selbst entfernt, ist dies etwas komplizierter. Sie müssen sich auf den Delegaten innerhalb des Lambda-Ausdrucks selbst beziehen, und Sie können dies nicht mit einer einfachen "Deklaration einer lokalen Variablen und Zuweisung" tun dazu einen Lambda - Ausdruck ", weil dann die Variable nicht eindeutig zugeordnet ist. In der Regel umgehen Sie dies, indem Sie der Variablen zuerst einen Nullwert zuweisen:

EventHandler handler = null;
handler = (sender, args) =>
{
    button.Click -= handler; // Unsubscribe
    // Add your one-time-only code here
}
button.Click += handler;

Leider ist es nicht einmal einfach, dies in eine Methode zu kapseln, da Ereignisse nicht sauber dargestellt werden. Der nächste, dem Sie kommen könnten, wäre etwa:

button.Click += Delegates.AutoUnsubscribe<EventHandler>((sender, args) =>
{
    // One-time code here
}, handler => button.Click -= handler);

Selbst das wäre schwierig in Delegates.AutoUnsubscribe Zu implementieren, da Sie ein neues EventHandler erstellen müssten (was nur ein generisches Typargument wäre). Machbar, aber chaotisch.

313
Jon Skeet