2010-08-31 7 views
5

Ho visto alcune persone che si appoggiavano ai metodi di callback/eventi e poi a volte li distribuivano a lambda.in abbonamento vs delega lambda - Quale e perché?

Qualcuno può parlare con qualsiasi differenza tra i due? All'inizio avrei pensato che fossero uguali, ma l'incoerenza che ho visto implementato a volte mi fa chiedere se c'è un caso in cui uno è preferibile rispetto all'altro? Ovviamente se c'è un numero molto grande di codice non dovrebbe essere un lambda posto, ma per il resto ..

Puoi tutti delineare eventuali differenze tra i due se del caso e delineare le regole che si utilizzano nella scelta tra i due quando entrambi sono disponibili?

risposta

7

Una delle maggiori differenze tra i due è la facilità con cui è possibile annullare l'iscrizione all'evento. Con il metodo basato approccio unsubscribing è un'operazione semplice, è sufficiente utilizzare il metodo originale

m_button.Click += OnButtonClick; 
... 
m_button.Click -= OnButtonClick; 

con lambda questo non è così semplice. È necessario riporre l'espressione lambda e per essere usato in seguito per unsbuscribe dall'evento

m_button.Click += delegate { Console.Write("here"); } 
... 
// Fail 
m_button.Click -= delegate { Console.Write("here"); } 

EventHandler del = delegate { Console.Write("here"); } 
m_button.Click += del; 
... 
m_button.Click -= del; 

Si toglie davvero dalla comodità di utilizzo di espressioni lambda.

+0

Ho preso l'abitudine di + = (sender, e) => {} e non ci ho mai pensato ma non potevo rimuovere quel listener specifico se volevo, buon punto .. –

+0

@Jimmy, spesso volte non è necessario e questo punto diventa irrilevante. Ma è fastidioso quando lo fai. – JaredPar

2

Nella maggior parte delle lingue con lambda (incluso C#), la creazione di un lambda all'interno di un metodo crea una chiusura, ovvero le variabili locali all'interno del metodo di dichiarazione saranno visibili al lambda. Questa è la più grande differenza di cui sono a conoscenza.

A parte questo, a meno che non si chiami il gestore di eventi in qualche modo, in un modo accessibile in un'altra funzione, sarà difficile staccare il gestore di eventi in un secondo momento. Ciò è fattibile memorizzando il delegato in una variabile a livello di istanza o classe, ma può essere un po 'brutto.

1

Il motivo principale per l'utilizzo di un Lambda è di ritardare l'esecuzione, ovvero definire le operazioni che si desidera eseguire, ma non si avranno i parametri fino a più tardi. Generalmente non usi lambda per eventi e callback; usi metodi anonimi.

L'utilizzo di metodi anonimi per eventi e callback va bene per eventi semplici a cui non è necessario annullare l'iscrizione. Il più grande fattore determinante per me è dove lo sto dichiarando. Non ho intenzione di dichiarare un gestore di eventi per un modulo come metodo anonimo, ma se ho una necessità di breve durata di connettersi a un evento, potrebbe andare bene.

In generale, utilizzo metodi effettivi per richiamate ed eventi più che metodi anonimi; gli eventi che sto gestendo sono legati alla durata dell'oggetto, non alla durata del metodo, e trovo che sia più chiaro nel codice che i callback siano chiaramente definiti esterni alla funzione che li aggancia. Alcuni di questi sono preferenze personali.

+1

Lambdas non viene ritardato nel normale senso della parola. Sono solo delegati e hanno un normale comportamento delegato. In genere l'esecuzione ritardata viene utilizzata per descrivere le query LINQ che hanno semantica diversa da lambda. – JaredPar

+0

Hai ragione, buon punto. LINQ è il luogo in cui utilizzo principalmente Lambdas, la distinzione si è confusa nella mia testa –

0

Nella maggior parte dei casi, c'è poca differenza pratica. Quale utilizzare è principalmente una questione di preferenze personali (ad esempio, ciò che si desidera che il codice per appaia come). In alcuni casi, ci sono alcune ragioni pratiche per preferire uno sopra l'altro:

  1. Come osservato in the accepted answer, l'annullamento dell'iscrizione un metodo anonimo è più complessa di disdire un metodo denominato. Senza un nome, non c'è modo di fare riferimento al metodo anonimo tranne che all'istanza delegata creata in fase di esecuzione in cui viene dichiarato il metodo anonimo. Utilizzando un metodo denominato, il delegato può essere annullato senza aver conservato un riferimento al delegato originale (o al suo equivalente).
  2. D'altra parte, un motivo per preferire un'espressione lambda è quando il gestore per l'evento è un dettaglio di implementazione univoco per il metodo denominato in cui viene dichiarato il metodo lambda/anonimo. Ciò può aiutare a mantenere tali dettagli di implementazione privati ​​e locali nel metodo in cui vengono utilizzati.
  3. Un'altra ragione per cui si potrebbe usare un'espressione lambda è se è necessario "adattare" il tipo di delegato. Cioè vuoi chiamare un metodo chiamato per gestire l'evento, ma quel metodo ha una firma diversa da quella richiesta dall'evento. Questo potrebbe essere il caso in cui si desidera riutilizzare il metodo per eventi diversi o altre situazioni, in cui alcuni dei parametri dell'evento potrebbero non essere applicabili. Un altro caso potrebbe essere il punto in cui si desidera introdurre un nuovo parametro, un valore per il quale l'evento potrebbe non fornire (ad esempio un indice per una raccolta di oggetti che hanno tutti lo stesso evento a cui si desidera sottoscrivere).

C'è un caso speciale che a volte può sorgere, che è la scelta se utilizzare un metodo con nome da solo oppure utilizzare un metodo anonimo che chiama quel metodo denominato. È importante notare che, in assenza di altri motivi pratici per scegliere l'uno rispetto all'altro, l'utilizzo di un metodo denominato è leggermente più efficiente in questo caso particolare, perché rimuove una chiamata al metodo dall'invocazione. In pratica, probabilmente non noterai mai la differenza, ma è solo un sovraccarico, quindi se non c'è una ragione pratica specifica per sostenerlo, probabilmente dovresti evitarlo, ad esempio iscriviti direttamente al metodo denominato.