2009-04-30 13 views
26

Tengo el siguiente código para permitir que la GUI responda a un cambio en la colección.¿Cómo darse de baja de un evento que utiliza una expresión lambda?

myObservableCollection.CollectionChanged += ((sender, e) => UpdateMyUI()); 

¿En primer lugar es esta una buena manera de hacer esto?

Segundo: ¿cuál es el código para darse de baja de este evento? ¿Es lo mismo pero con - = (y luego el método anónimo completo nuevamente)?

+0

? Duplicado: http://stackoverflow.com/questions/183367/unsubscribe-anonymous-method-in-c – Richard

+0

Ver [esto] (http://stackoverflow.com/questions/183367/unsubscribe-anonymous-method -Cª). –

+0

No puse mi expresión lambda en un delegado (como en su enlace), así que no tengo una referencia para cancelar la suscripción. –

Respuesta

20

Si necesita darse de baja de un evento, necesita una referencia instanciada. Desafortunadamente, eso significa que no puedes usar esa sintaxis en particular.

+2

Si por "esa sintaxis particular" te refieres a crear el lambda y agregar el controlador en una línea, entonces sí. La solución simple es simplemente almacenar una referencia a la lambda. En realidad, creo que el OP debería tener en cuenta el uso de un método común si necesita referenciarlo repetidamente; mejora la legibilidad, al menos en mi mente. – Noldorin

+0

Gracias por aclarar esto. –

+0

@Noldorin Sí, eso es lo que quise decir con "esa sintaxis particular". Y estoy totalmente de acuerdo contigo. –

35

En primer lugar ... sí, es una buena forma de hacerlo, es limpio, de forma pequeña y fácil de leer & entender ... la advertencia por supuesto es "A menos que quieras cancelar la subscripción".

Creo que Jon Skeet señaló antes que "la especificación explícitamente no garantiza el comportamiento de ninguna manera cuando se trata de equivalencia de delegados creados con métodos anónimos".

Por lo tanto, si necesita darse de baja del evento más adelante, sería mejor que cree una instancia de delegado para que pueda conservar la referencia para más adelante.

var myDelegate = delegate(sender, e){UpdateMyUI()}; 

myObservableCollection.CollectionChanged += myDelegate; 

myObservableCollection.CollectionChanged -= myDelegate; 
+0

var myDelegate = delegate (remitente, e) {UpdateMyUI()}; no compila ... necesita especificar el tipo de delegado. John Skeet usa el delegado de Acción en su ejemplo, pero eso solo toma un argumento. ¿Qué tipo de delegado deberíamos usar en tu ejemplo? –

+1

@RaduSimionescu: Igual que el tipo del evento, que en este ejemplo sería 'NotifyCollectionChangedEventHandler' –

1

Es una manera bien para ir, a menos que myObservableCollection va a vivir más que 'esto', en cuyo caso se podría terminar con una pérdida de memoria, como el delegado que se crea detrás de las escenas conservará una referencia a tu 'esto', que lo mantendrá vivo. Si está creando y 'destruyendo' repetidamente lo que sea que esté escuchando el evento, descubrirá que no lo está recogiendo el recolector de basura.

Si esto es un problema, puede seguir la ruta sugerida en las respuestas, conservando una referencia al manejador, que debe crear primero.

Otra solución es utilizar referencias débiles para crear un controlador de eventos que permitirá que el suscriptor se recopile si no hay otras referencias. Exploré esta solución en this question and answer.

Cuestiones relacionadas