Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reactive Observable Subscription Disposal

If I have access to an IObservable that I know is only ever going to return one item, will this work and is it the best usage pattern?

IDisposable disposable = null; disposable = myObservable.Subscribe(x =>   {      DoThingWithItem(x);      if (disposable != null)      {        disposable.Dispose();      }   }); 
like image 287
Noob Avatar asked Oct 09 '11 12:10

Noob


2 Answers

The disposable returned by the Subscribe extension methods is returned solely to allow you to manually unsubscribe from the observable before the observable naturally ends.

If the observable completes - with either OnCompleted or OnError - then the subscription is already disposed for you.

Try this code:

var xs = Observable.Create<int>(o => {     var d = Observable.Return(1).Subscribe(o);     return Disposable.Create(() =>     {         Console.WriteLine("Disposed!");         d.Dispose();     }); });  var subscription = xs.Subscribe(x => Console.WriteLine(x)); 

If you run the above you'll see that "Disposed!" is written to the console when the observable completes without you needing call .Dispose() on the subscription.

One important thing to note: the garbage collector never calls .Dispose() on observable subscriptions, so you must dispose of your subscriptions if they have not (or may not have) naturally ended before your subscription goes out of scope.

Take this, for example:

var wc = new WebClient();  var ds = Observable     .FromEventPattern<         DownloadStringCompletedEventHandler,         DownloadStringCompletedEventArgs>(             h => wc.DownloadStringCompleted += h,             h => wc.DownloadStringCompleted -= h);  var subscription =     ds.Subscribe(d =>         Console.WriteLine(d.EventArgs.Result)); 

The ds observable will only attach to the event handler when it has a subscription and will only detach when the observable completes or the subscription is disposed of. Since it is an event handler the observable will never complete because it is waiting for more events, and hence disposing is the only way to detach from the event (for the above example).

When you have a FromEventPattern observable that you know will only ever return one value then it is wise to add the .Take(1) extension method before subscribing to allow the event handler to automatically detach and then you don't need to manually dispose of the subscription.

Like so:

var ds = Observable     .FromEventPattern<         DownloadStringCompletedEventHandler,         DownloadStringCompletedEventArgs>(             h => wc.DownloadStringCompleted += h,             h => wc.DownloadStringCompleted -= h)     .Take(1); 

I hope this helps.

like image 77
Enigmativity Avatar answered Sep 19 '22 11:09

Enigmativity


Disclaimer: I'm also still learning Rx. So I'm not really an expert but I believe the disposable returned by Subscribe will only unsubscribe the subscription. Also if the source completes, like in your case, the unsubscription is done automatically. So I think the Dispose there is redundant and can be safely removed.

See the answer to this question for more info.

like image 34
Ilian Avatar answered Sep 21 '22 11:09

Ilian