2010-01-12 6 views
46

Me preguntaba si esto realmente funcionó?Agregar y eliminar el controlador de eventos anónimos

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

¿Cómo sabe el compilador que los controladores de eventos son iguales? ¿Esto es incluso recomendado?

+0

duplicado Posible de [método anónimo Darse de baja en C#] (https://stackoverflow.com/questions/183367/unsubscribe-anonymous-method-in-c-sharp) –

Respuesta

55

Hay una página de MSDN que habla de esto:

How to Subscribe to and Unsubscribe from Events

nota en particular:

Si usted no tendrá que darse de baja de [sic] un evento posterior, puede utilice el operador de asignación de suma (+ =) a adjunte un método anónimo al evento .

Y también:

Es importante notar que no puede darse de baja fácilmente de un evento si se ha utilizado una función anónima suscribirse a él. Para darse de baja en este escenario, es necesario volver al código donde se suscribe al evento, almacenar el método anónimo en una variable de delegado, y luego agrega el delegado de el evento. En general, recomendamos que no use funciones anónimas para suscribirse a eventos si tendrá que darse de baja del evento en algún momento posterior en su código .

+0

Entonces, ¿significa que básicamente lo que está en OP no funciona como se supone? ¿Significa que el delegado anónimo, si no está almacenado en el punto de suscripción, es casi imposible cancelar la suscripción? –

+0

Obviamente, sí. –

1

Si consulta con el documento para Delegate.Equality, descubrirá que no se comparan por referencia.

3

No creo que esto funcione. Si realmente necesita cancelar el registro de un evento, debe especificar un controlador de eventos explícito del que luego puede cancelar el registro en lugar de un delegado anónimo.

2

Eso no funcionará, me temo, ya que las dos expresiones lambda (y delegados) que ha declarado son en realidad objetos diferentes, y devuelve referencias diferentes. Por lo tanto, la eliminación del controlador (-=) siempre fallará.

La solución común a este problema (donde debe quitar el controlador) es simplemente refactorizar la expresión lamba en un método adecuado. Una alternativa es mantener una variable de clase para el delegado controlador de eventos, y agregar y eliminar esto, aunque personalmente no soy un fanático de él. (Es más complicado que crear un método normal, en todo caso).

+0

Tenga en cuenta que hay una pregunta y respuesta bastante similar en , donde Reed Copsey sugiere la misma solución que yo. . – Noldorin

5

Si necesita anular la suscripción de un controlador de eventos, deberá tener una referencia definitiva a un delegado concreto. Si mira Delegate.Equality, encontrará que los delegados no solo se comparan utilizando la igualdad de referencia, sin embargo, esto no tiene importancia para los delegados anónimos.

Para un delegado anónimo, el compilador (básicamente) acaba de crear un nuevo delegado "no anónimo" para cada delegado anónimo, incluso si los cuerpos delegados son los mismos. Debido a esto, el marco no encontrará al delegado para darse de baja cuando use el código que dio.

8

Para cualquier persona interesada, puede añadir y eliminar un controlador de eventos en el anonimato como esto

public class Musician 
{ 
    public void TuneGuitar() 
    { 
     Metronome metronome = new Metronome(); 

     EventHandler<EventArgs> 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<EventArgs> Tick; 
} 

ACTUALIZACIÓN: En C# 7.0 tenemos soportes para local functions lo que el método TuneGuitar ahora se puede escribir como:

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; 
} 
Cuestiones relacionadas