I'm using Reactive Extensions for easy event handling in my ViewModels (Silverlight and/or Wp7 apps). For sake of simplicity let's say I have a line like this in the ctor of my VM:
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*/});
this returns an IDisposable object, which if disposed will unsubscribe. (Am I right in this assumption?)
If I hold no reference to it, sooner or later it will be collected, and my handler will be unsubscribed.
I usually have a List<IDisposable>
in my VM, and I add subscriptions to it, yet I feel dirty about it, as if I'm not doing something in a correct Rx way.
What is the best practice, recommended pattern on situations like this?
Your first assumption is correct, the IDisposable is for unsubscribing. However, you do not need to hold a reference to the IDisposable to prevent your observer from being collected. The IObservable will need to keep a reference to the observer to be able to call its methods, thus keeping the observer alive as long as the observable is alive.
The astute reader will realize that I am somewhat begging the question, because I have assumed that the observable will not be collected. To deal with that issue, let's make some reasonable guesses about what's going on behind the scenes. The first observable is subscribing to an event. This means that the object with the event has a reference to our observer from the time we subscribe to the time we unsubscribe. Since Rx operators must at some point subscribe to their sources, one can assume that the event observer has a reference to the Where observer, which has a reference to the Throttle observer, which of course is referring to our final observer.
Since we kept no way to unsubscribe, this ties the life of the observer to the life of the object with the event. Without full knowledge of your program, that is all the farther up the chain I can go, but I think it should be sufficient for you to determine the lifetime of the observable.
This actually points out a potential "memory leak" that you can have with standard .NET events, objects keeping all their event subscribers alive, which leads to your second question. If you do not keep a reference to the IDisposable, you will never be able to unsubscribe from the event and your object will continue to receive notices, even after you close the view it is related to. If the event source does not live longer than the view, this may not be a problem, but I recommend using the disposable.
There is nothing "un-Rx" about this, and Rx even includes a nice class to use as an alternative to the List if you want, System.Reactive.Disposables.CompositeDisposable
.
Gideon is incorrect here. The semantics of how Rx use IDisposable are different than typical .NET. The IDisposable returned from Subscribe is if you want to unsubscribe earlier than the end of the IObservable. If you don't want to do this, complicating your code with all of the extra disposable management is unnecessary.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With