Utilisation d'expressions lambda pour les gestionnaires d'événements

114

J'ai actuellement une page qui est déclarée comme suit:

public partial class MyPage : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        //snip
        MyButton.Click += (o, i) =>
        {
            //snip
        }
    }
}

Je ne suis que récemment passé à .NET 3.5 à partir de la version 1.1, je suis donc habitué à écrire des gestionnaires d'événements en dehors de Page Load. Ma question est; y a-t-il des inconvénients ou des pièges de performance à surveiller lors de l'utilisation de la méthode lambda pour cela? Je le préfère, car il est certainement plus concis, mais je ne veux pas sacrifier les performances pour l'utiliser. Merci.

Christopher Garcia
la source

Réponses:

117

Il n'y a aucune implication sur les performances puisque le compilateur traduira votre expression lambda en un délégué équivalent. Les expressions Lambda ne sont rien de plus qu'une fonctionnalité de langage que le compilateur traduit exactement dans le même code avec lequel vous avez l'habitude de travailler.

Le compilateur convertira le code que vous avez en quelque chose comme ceci:

public partial class MyPage : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        //snip
        MyButton.Click += new EventHandler(delegate (Object o, EventArgs a) 
        {
            //snip
        });
    }
}
Andrew Hare
la source
Je vois. N'y a-t-il donc pas non plus d'inconvénient à avoir ces gestionnaires à l'intérieur de Page Load au lieu de les avoir à l'extérieur?
Christopher Garcia
1
La convention qui prévaut est d'attacher des gestionnaires d'événements dans la OnInitméthode, mais comme l' Clickévénement d' un bouton sera déclenché après le chargement de la page, cet exemple convient.
Andrew Hare
8
Il est important de noter que sans conserver une référence au délégué, vous ne pouvez pas vous désabonner de l'événement.
snarf
3
"le même code exact" est un peu trompeur; au moins lors du référencement des variables locales à partir de la méthode englobante, les expressions lambda ne sont pas traduites en méthodes et quelque chose comme un objet de fermeture qui stocke les valeurs actuelles des variables locales.
OR Mapper
66

En termes de performances, c'est la même chose qu'une méthode nommée. Le gros problème est lorsque vous effectuez les opérations suivantes:

MyButton.Click -= (o, i) => 
{ 
    //snip 
} 

Il essaiera probablement de supprimer un lambda différent, en y laissant l'original. Donc, la leçon est que tout va bien à moins que vous ne souhaitiez également pouvoir supprimer le gestionnaire.

Gabe
la source
3
"Il essaiera probablement de ..."? Enlèvera-t-il jamais le bon gestionnaire dans une telle situation?
OR Mapper
1
@ORMapper: Si le lambda capture une variable, il ne peut pas supprimer le bon gestionnaire. Dans d'autres circonstances, c'est au compilateur.
Gabe
Vraiment? Intéressant - donc, si j'enregistre deux fonctions anonymes qui se ressemblent (wlog a un corps vide), puis que je désinscris (en utilisant -=) une autre fonction anonyme qui a aussi un corps vide, il est essentiellement indéfini lequel des deux gestionnaires d'événements sera être supprimé, ou si l'un d'entre eux sera supprimé du tout?
OR Mapper
4
@ORMapper: Oui. Le compilateur est autorisé (mais pas obligé) à créer des délégués égaux s'ils ont une sémantique identique (le code ne doit pas être le même, mais ils doivent faire la même chose) et capturer les mêmes instances de variables (pas seulement les mêmes variables, mais les mêmes instances de ces variables). Voir la section 7.10.8 (Opérateurs d'égalité délégués) de la spécification C # pour tous les détails.
Gabe
12
Si vous voulez vraiment utiliser le lambda mais que vous devez supprimer l'événement, vous pouvez toujours garder l'objet dans une variable / champ local puis le supprimer, par exemplevar event = (o, e) => doSomething(); handler += event; doSomethingElse(); handler -= event;
Wai Ha Lee
44
EventHandler handler = (s, e) => MessageBox.Show("Woho");

button.Click += handler;
button.Click -= handler;
usama wahab khan
la source
1
Information très utile, bien que hors sujet (la question porte sur les performances).
Stéphane Gourichon
4
Pas vraiment hors sujet car l'utilisation de la mémoire peut entraîner une dégradation des performances.
Vladius
3
c# EventHandler handler = null; handler = (s, e) => { MessageBox.Show("Woho"); button.Click -= handler;}
Se retirer
2

Aucune implication sur les performances que je connaisse ou que j'ai jamais rencontrée, pour autant que je sache, c'est juste un "sucre syntaxique" et se compile à la même chose que l'utilisation de la syntaxe de délégué, etc.

Heisenberg
la source