web-dev-qa-db-fra.com

Comment supprimer un gestionnaire d'événements lambda

Doublons possibles:
Méthode anonyme avec désinscription en C #
Comment désenregistrer un gestionnaire d’événements ‘anonymous’

J'ai récemment découvert que je pouvais utiliser lambdas pour créer de simples gestionnaires d'événements. Je pourrais par exemple m'abonner à un événement de clic comme ceci:

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

Mais comment voudriez-vous vous désabonner?

220
Svish

La spécification C # indique explicitement (IIRC) que si vous avez deux fonctions anonymes (méthodes anonymes ou expressions lambda), vous pouvez créer ou non des délégués égaux à partir de ce code. (Deux délégués sont égaux s'ils ont des objectifs égaux et font référence aux mêmes méthodes.)

Pour être sûr, vous devez vous rappeler l'instance de délégué que vous avez utilisée:

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

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

(Je ne trouve pas le bit pertinent dans la spécification, mais je serais très surpris de voir le compilateur C # essayer agressivement de créer des délégués égaux. Il ne serait certainement pas sage de s'en fier.)

Si vous ne voulez pas faire cela, vous devrez extraire une méthode:

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

...

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

Si vous voulez créer un gestionnaire d'événements qui se supprime lui-même en utilisant une expression lambda, c'est un peu plus compliqué - vous devez faire référence au délégué dans l'expression lambda elle-même, et vous ne pouvez pas le faire avec un simple "déclarer une variable locale et affecter à l'aide d'une expression lambda "car la variable n'est pas définitivement affectée. Vous contournez généralement ceci en assignant une valeur null à la variable en premier:

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

Malheureusement, il n'est même pas facile d'incorporer ceci dans une méthode, car les événements ne sont pas représentés correctement. Le plus proche que vous pourriez venir serait quelque chose comme:

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

Même cela serait difficile à mettre en œuvre au sein de Delegates.AutoUnsubscribe parce qu'il faudrait créer un nouveau EventHandler (qui ne serait qu'un argument de type générique). Faisable, mais désordonné.

313
Jon Skeet