Aggiunta e rimozione di gestore eventi anonimo

Mi stavo chiedendo se questo effettivamente ha funzionato?

private void RegisterKeyChanged(T item) { item.OnKeyChanged += (o, k) => ChangeItemKey((T)o, k); } private void UnRegisterKeyChanged(T item) { item.OnKeyChanged -= (o, k) => ChangeItemKey((T)o, k); } 

Come fa il compilatore a sapere che i gestori di eventi sono gli stessi? E ‘anche raccomandato?

C’è una pagina MSDN che parla di questo:

Come iscriversi e cancellarsi dagli eventi

Nota in particolare:

Se non è necessario annullare l’iscrizione a [sic] un evento in un secondo momento, è ansible utilizzare l’operatore di assegnazione addizione (+ =) per albind un metodo anonimo all’evento.

E anche:

È importante notare che non è ansible annullare facilmente l’iscrizione a un evento se si è utilizzata una funzione anonima per iscriversi ad esso. Per annullare l’iscrizione in questo scenario, è necessario tornare al codice in cui si sottoscrive l’evento, memorizzare il metodo anonimo in una variabile delegata e quindi aggiungere il delegato all’evento. In generale, ti consigliamo di non utilizzare le funzioni anonime per iscriverti agli eventi se dovrai annullare l’iscrizione all’evento in un momento successivo del tuo codice.

Per chiunque sia interessato, è ansible aggiungere e rimuovere un gestore di eventi anonimo come questo

 public class Musician { public void TuneGuitar() { Metronome metronome = new Metronome(); EventHandler handler = null; handler = (sender, args) => { // Tune guitar // ... // Unsubscribe from tick event when guitar sound is perfect metronome.Tick -= handler; }; // Attach event handler metronome.Tick += handler; } } public class Metronome { event EventHandler Tick; } 

AGGIORNAMENTO: In C # 7.0 abbiamo supporti per le funzioni locali, quindi il metodo TuneGuitar può ora essere scritto come:

 public void TuneGuitar() { Metronome metronome = new Metronome(); void handler = (object sender, EventArgs args) => { // Tune guitar // ... // Unsubscribe from tick event when guitar sound is perfect metronome.Tick -= handler; }; // Attach event handler metronome.Tick += handler; } 

Se è necessario annullare l’iscrizione a un gestore di eventi, è necessario avere un riferimento preciso a un delegato concreto. Guardando a Delegate.Equality scoprirai che i delegati non vengono solo confrontati usando l’uguaglianza di riferimento, ma questo non importa per i delegati anonimi.

Per un delegato anonimo, il compilatore (in pratica) crea semplicemente un nuovo delegato “non anonimo” per ciascun delegato anonimo, anche se i corpi dei delegati sono gli stessi. Per questo motivo, il framework non troverà il delegato per annullare l’iscrizione quando si utilizza l’esempio di codice che hai fornito.

Non funzionerà, ho paura, dal momento che le due espressioni lambda (e delegati) che hai dichiarato sono in realtà oggetti diversi e restituiscono riferimenti diversi. Quindi, la rimozione del gestore ( -= ) fallirà sempre.

La soluzione comune a questo problema (in cui è necessario rimuovere il gestore) è semplicemente il refactoring dell’espressione di lamba in un metodo corretto. Un’alternativa è mantenere una variabile di class per il delegato del gestore di eventi e aggiungere e rimuovere questo, sebbene personalmente non ne sia un fan. (È più complicato che creare un metodo normale, se non altro).

Non credo che funzionerà. Se è davvero necessario annullare la registrazione da un evento, è necessario specificare un gestore eventi esplicito che è ansible in seguito annullare la registrazione anziché un delegato anonimo.

Se si seleziona il documento con Delegate.Equality, si scoprirà che non vengono confrontati per riferimento.