Utilizzo di espressioni lambda per gestori di eventi


114

Al momento ho una pagina dichiarata come segue:

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

Sono passato solo di recente a .NET 3.5 da 1.1, quindi sono abituato a scrivere gestori di eventi al di fuori di Page_Load. La mia domanda è; ci sono svantaggi o insidie ​​nelle prestazioni a cui dovrei prestare attenzione quando utilizzo il metodo lambda per questo? Lo preferisco, in quanto è sicuramente più conciso, ma non voglio sacrificare le prestazioni per usarlo. Grazie.

Risposte:


117

Non ci sono implicazioni sulle prestazioni poiché il compilatore tradurrà l'espressione lambda in un delegato equivalente. Le espressioni lambda non sono altro che una funzionalità del linguaggio che il compilatore traduce nello stesso identico codice con cui sei abituato a lavorare.

Il compilatore convertirà il codice che hai in qualcosa del genere:

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
        });
    }
}

Vedo. Quindi non c'è alcun inconveniente nell'avere questi gestori all'interno di Page_Load rispetto ad averli al di fuori di esso?
Christopher Garcia

1
La convenzione prevalente è quella di collegare i gestori di eventi nel OnInitmetodo, ma poiché l' Clickevento di un pulsante verrà generato dopo il caricamento della pagina, questo esempio va bene.
Andrew Hare

8
È importante notare che senza mantenere un riferimento al delegato, non è possibile annullare l'iscrizione all'evento.
Snarf

3
"lo stesso identico codice" è un po 'fuorviante; almeno quando si fa riferimento a variabili locali dal metodo di inclusione, le espressioni lambda non vengono tradotte in metodi e qualcosa di simile a un oggetto di chiusura che memorizza i valori correnti delle variabili locali.
OR Mapper

66

Dal punto di vista delle prestazioni è lo stesso di un metodo denominato. Il grosso problema è quando fai quanto segue:

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

Probabilmente proverà a rimuovere un lambda diverso, lasciando quello originale lì. Quindi la lezione è che va bene a meno che tu non voglia anche essere in grado di rimuovere il gestore.


3
" Probabilmente proverà a ..."? Sarà mai rimuovere il corretto gestore in tale situazione una?
OR Mapper

1
@ORMapper: se lambda acquisisce una variabile, non può rimuovere il gestore corretto. In altre circostanze, dipende dal compilatore.
Gabe

Veramente? Interessante - quindi, se registro due funzioni anonime che hanno lo stesso aspetto (wlog ha un corpo vuoto), e poi annullo (usando -=) un'altra funzione anonima che ha anch'essa un corpo vuoto, è essenzialmente indefinito quale dei due gestori di eventi lo farà essere rimosso o se qualcuno di loro verrà rimosso del tutto?
OR Mapper

4
@ORMapper: Sì. Il compilatore può (ma non deve) creare delegati uguali se hanno semantica identica (il codice non deve essere lo stesso, ma devono fare la stessa cosa) e catturare le stesse istanze di variabili (non solo il stesse variabili, ma le stesse istanze di quelle variabili). Vedere la sezione 7.10.8 (Operatori di uguaglianza delega) delle specifiche C # per tutti i dettagli.
Gabe

12
Se vuoi davvero usare lambda ma devi rimuovere l'evento, puoi sempre mantenere l'oggetto in una variabile / campo locale, quindi rimuoverlo, ad esempiovar 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;

1
Informazioni molto utili, anche se fuori tema (la domanda riguarda le prestazioni).
Stéphane Gourichon

4
Non esattamente fuori tema poiché l'utilizzo della memoria può portare a un downgrade delle prestazioni.
Vladius

3
Anche la rimozione di se stessa in un gestore stesso può essere utile:c# EventHandler handler = null; handler = (s, e) => { MessageBox.Show("Woho"); button.Click -= handler;}
Vladius

2

Nessuna implicazione sulle prestazioni di cui sono a conoscenza o in cui mi sono mai imbattuto, per quanto ne so è solo "zucchero sintattico" e si compila alla stessa cosa dell'uso della sintassi del delegato, ecc.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.