2012-01-17 13 views
6

Estoy usando Reactive Extensions para facilitar el manejo de eventos en mis ViewModels (aplicaciones Silverlight y/o Wp7). En aras de la simplicidad vamos a decir que tengo una línea como esta en el ctor de mi VM:¿Qué hacer con los servidores IObster desechados?

Observable.FromEvent<PropertyChangedEventArgs>(
          h => MyObject.PropertyChanged += h, 
          h => MyObject.PropertyChanged -= h) 
    .Where(e=>e.PropertyName == "Title") 
    .Throttle(TimeSpan.FromSeconds(0.5)) 
    .Subscribe(e=>{/*do something*/}); 

Esto devuelve un objeto IDisposable, , que si se echa va a darse de baja.(¿Estoy en lo correcto en esta suposición?)
Si no tengo ninguna referencia, tarde o temprano se recogerá y mi manejador será anulado.

Normalmente tengo un List<IDisposable> en mi VM, y le agrego suscripciones, pero me siento sucio al respecto, como si no estuviera haciendo algo de la manera correcta de Rx.

¿Cuál es la mejor práctica, patrón recomendado en situaciones como esta?

Respuesta

9

Su primera suposición es correcta, la IDisposable es para darse de baja. Sin embargo, no es necesario que guardes una referencia al IDisposable para evitar que tu observador sea recogido. El IObservable necesitará mantener una referencia al observador para poder invocar sus métodos, manteniendo así al observador vivo mientras el observable esté vivo.

El lector astuto se dará cuenta de que estoy de alguna manera mendigando la pregunta, porque he supuesto que lo observable no se recogerá. Para lidiar con ese problema, hagamos algunas conjeturas razonables sobre lo que está sucediendo detrás de escena. El primer observable es suscribirse a un evento. Esto significa que el objeto con el evento tiene una referencia a nuestro observador desde el momento en que nos suscribimos hasta el momento en que cancelamos la suscripción. Como los operadores Rx deben en algún momento suscribirse a sus fuentes, se puede suponer que el observador del evento tiene una referencia al observador Where, que tiene una referencia al observador del acelerador, que por supuesto se refiere a nuestro observador final.

Como no pudimos anular la suscripción, esto vincula la vida del observador con la vida del objeto con el evento. Sin un conocimiento completo de tu programa, eso es lo más avanzado que puedo llegar a la cadena, pero creo que debería ser suficiente para determinar la duración de la vida observable.

Esto realmente señala una posible "pérdida de memoria" que puede tener con los eventos .NET estándar, objetos que mantienen vivos a todos sus suscriptores de eventos, lo que lleva a su segunda pregunta. Si no mantiene una referencia al IDisposable, nunca podrá darse de baja del evento y su objeto continuará recibiendo avisos, incluso después de cerrar la vista con la que está relacionado. Si el origen del evento no dura más que la vista, esto puede no ser un problema, pero recomiendo usar el desechable.

No hay nada "no-Rx" al respecto, y Rx incluso incluye una buena clase para usar como alternativa a la Lista si lo desea, System.Reactive.Disposables.CompositeDisposable.

+0

Sé acerca de la pérdida de eventos de memoria .NET, pero me salté el hecho de que no importa que IObservable disponga los observadores en Finalize, porque finalize no se llama aquí ... ¡Gracias! – TDaver

+1

Si estuviera especificando cómo 'IObservable ' debe comportarse y debe usarse, especifico que cada consumidor escrito apropiadamente debe mantener una referencia al 'IDisposable' devuelto en algún lugar, y las implementaciones deben considerarse libres de (si no se recomienda) cancelar cualquier suscripción cuyo 'IDisposable' asociado esté fuera del alcance. – supercat

-1

La práctica común es implementar la interfaz IDisposable y desechar sus miembros desechables aquí.

+0

quieres decir hacer que mi VM implemente IDisposable? ¿Quién llamará a disponer de eso?(¿O debería implementar un patrón de disposición con un finalizador?) – TDaver

+0

@TDaver Es responsabilidad del cliente llamar a 'Dispose', por lo que depende de la instancia de su objeto. –

6

Gedeón no está correctamente aquí. La semántica de cómo Rx usa IDisposable es diferente de .NET típico. El IDisposable devuelto desde Suscribir es si desea darse de baja anterior que el final de IObservable. Si no quiere hacer esto, es innecesario complicar su código con toda la administración desechable adicional.

+0

Entonces, si mi fuente de eventos genera OnCompleted, ¿todo se anulará automáticamente? – TDaver

+0

TDaver: Sí, lo hará –

+0

Sí, pero los "eventos" no se completarán nunca. Eso es para usar Streams observables y similares. Así que sí necesito la idea de Gideon, mientras que también es correcto, obviamente ... – TDaver

Cuestiones relacionadas