Anonymous delegates/methods/lambda… unsubscribing…
Sappiamo tutti cosa sono gli eventi e come utilizzarli/gestirli, abbiamo il sistema tradizionale (quasi legacy oserei dire ;-)):
WithEvent we = new WithEvent(); we.SomethingOccurred += new EventHandler( OnSomethingOccurred );In cui agganciamo esplicitamente un delegate, che punta ad un nostro metodo, all’evento esposto da una classe.
Abbiamo poi altri due sistemi, il secondo evoluzione del primo, che sono decisamente più smart:
WithEvent we = new WithEvent(); we.SomethingOccurred += delegate( object sender, EventArgs e ) { //Do something... };possiamo infatti utilizzare gli anonymous methods per agganciare direttamente un handler, questo, oltre che ad una maggior leggibilità, porta anche una serie di vantaggi non indifferenti: uno su tutti la visibilità di eventuali variabili definite nello scope e la conseguente non necessità di gestire fastidiose variabili globali:
String foo = "foo"; WithEvent we = new WithEvent(); we.SomethingOccurred += delegate( object sender, EventArgs e ) { //Do something... foo = "new value"; };sarà onere del compilatore smazzarsi il problema, e lui è decisamente bravo.
Possiamo ulterirmente abbellire la sintassi facendo uso delle fantastiche lambda expression:
String foo = "foo"; WithEvent we = new WithEvent(); we.SomethingOccurred += ( s, e ) => { foo = "new value"; };ottenendo, imho, una sintassi semplicemente fenomenale.
Siamo però adesso di fronte ad un annoso problema, in entrambi gli ultimi 2 casi (anonymous methods e lambda) ci perdiamo per strada il fatto che sarebbe buona pratica anche rimuovere gli handler ad un evento. In questo purtroppo il compilatore non ci viene in aiuto perchè non genera nessun codice per la rimozione e così su 2 piedi ci troviamo di fronte ad piccolo inghippo di non facile soluzione… se infatti proviamo a scrivere sta “porcata” compila ma non sortisce l’effetto desiderato (e per fortuna aggiungo io…):
we.SomethingOccurred -= ( s, e ) => { foo = "new value"; };
questo perchè ogni volta che usiamo gli anonymous methods/lambda il compilatore genera degli handler diversi.
la soluzione però non è così brutta e neanche così ardua:
EventHandler handler = ( s, e ) => { foo = "new value"; }; we.SomethingOccurred += handler; we.SomethingOccurred -= handler;basta infatti crearlo noi l’handler… ma se volessimo deregistrare l’evento all’interno dell’handler stesso? potremmo essere tentati di scrivere una cosa del tipo:
String foo = "foo"; WithEvent we = new WithEvent(); EventHandler handler = ( s, e ) => { foo = "new value"; ( ( WithEvent )s ).SomethingOccurred -= handler; }; we.SomethingOccurred += handler;che è perfettamente lecito ma non compila… per il semplice fatto all’interno del corpo della lambda non posso far riferimento alla lambda stessa… in realtà questa cosa non è proprio vera e credo che il problema sia solo il compilatore che non è abbastanza smart, se infatti scriviamo:
EventHandler handler = null; handler = ( s, e ) => { foo = "new value"; ( ( WithEvent )s ).SomethingOccurred -= handler; };compila alla perfezione e funziona che è una meraviglia.
.m