2009-09-01 10 views
187

posibles duplicados:
Unsubscribe anonymous method in C#
How do I Unregister ‘anonymous’ event handlerCómo quitar un controlador de eventos lambda

Recientemente he descubierto que puedo usar lambdas para crear controladores de eventos simples. Podría, por ejemplo, suscribirme a un evento de clic como este:

button.Click += (s, e) => MessageBox.Show("Woho"); 

Pero, ¿cómo lo cancelarías?

+0

Vea aquí: http://stackoverflow.com/questions/183367 –

+0

¿Ha probado el operador - =? – Maciek

+1

@Svish: una lambda es esencialmente un método anónimo. – dtb

Respuesta

267

La especificación C# declara explícitamente (IIRC) que si tiene dos funciones anónimas (métodos anónimos o expresiones lambda) puede crear o no delegados iguales desde ese código. (Dos delegados son iguales si tienen objetivos iguales y se refieren a los mismos métodos.)

Para estar seguros, que había necesidad de recordar el ejemplo que utilizó delegado:

EventHandler handler = (s, e) => MessageBox.Show("Woho"); 

button.Click += handler; 
... 
button.Click -= handler; 

(no puedo encuentre el bit relevante de la especificación, pero me sorprendería bastante ver que el compilador de C# intenta agresivamente crear delegados iguales. Sin duda sería imprudente confiar en ello.)

Si no quiere hacer eso, necesitarás extraer un método:

public void ShowWoho(object sender, EventArgs e) 
{ 
    MessageBox.Show("Woho"); 
} 

... 

button.Click += ShowWoho; 
... 
button.Click -= ShowWoho; 

Si desea crear un controlador de eventos que se elimine utilizando una expresión lambda, es un poco más complicado: necesita referirse al delegado dentro de la expresión lambda, y no puede hacer eso con un simple "declare a local variable y asignarle usando una expresión lambda "porque entonces la variable no está definitivamente asignada. Por lo general, evitar esto mediante la asignación de un valor nulo a la primera variable:

EventHandler handler = null; 
handler = (sender, args) => 
{ 
    button.Click -= handler; // Unsubscribe 
    // Add your one-time-only code here 
} 
button.Click += handler; 

Por desgracia, no es fácil, incluso para encapsular esto en un método, porque los acontecimientos no están representados limpiamente. Lo más cerca que podría venir sería algo así como:

button.Click += Delegates.AutoUnsubscribe<EventHandler>((sender, args) => 
{ 
    // One-time code here 
}, handler => button.Click -= handler); 

Incluso eso sería difícil de poner en práctica dentro de Delegates.AutoUnsubscribe porque habría que crear una nueva EventHandler (que sería sólo un argumento de tipo genérico). Doable, pero desordenado.

+1

Exactamente, si mira dentro de su ensamblado compilado usando Reflector, notará que el compilador ha creado un puntero para usted de todos modos cuando utiliza lambda, es solo que no lo ve en Visual Studio – Raffaeu

+1

@ Raffaeu: llamarlo un puntero es un poco engañoso, no es un puntero en el sentido normal de C# de la palabra . –

+2

Sí, disculpe, "los compiladores crearán la variable controlador de todos modos" ¿es mejor? :) – Raffaeu

Cuestiones relacionadas