Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the purpose of returning an IDisposable in IObservable<T> interface?

I'm going through the Head First Design Patterns book and doing my best to convert the code from their Java to C#. After the book discussed the observer pattern it mentioned that Java has classes/interfaces built in, as does .NET4. So I began researching how to use it properly and I have most of it figured out except for the Subscribe() method.

If you look at the MSDN Article when you try subscribing an IObserver, the method returns an IDisposable. Why would that be necessary? Why not just implement a method that unsubcribes the IObserver based on a method argument? I researched the reason to use an IDisposable interface. I also read this but didn't quite understand the difference/what it was trying to tell me:

It returns a reference to an IDisposable interface. This enables observers to unsubscribe (that is, to stop receiving notifications) before the provider has finished sending them and called the subscriber's OnCompleted method.

like image 215
Adam Beck Avatar asked May 16 '12 20:05

Adam Beck


People also ask

What is the purpose of IDisposable interface?

Provides a mechanism for releasing unmanaged resources.

How is IDisposable interface implemented?

For implementing the IDisposable design pattern, the class which deals with unmanaged objects directly or indirectly should implement the IDisposable interface. And implement the method Dispose declared inside of the IDisposable interface.

What is IObservable in C#?

The IObservable<T> interface represents the class that sends notifications (the provider); the IObserver<T> interface represents the class that receives them (the observer). T represents the class that provides the notification information.


1 Answers

The information that is required to cancel a subscription will vary depending upon how the event publisher manages subscriptions. The approach used for events--passing to the Remove method the delegate previously passed to the Add method--is kinda sorta workable, but has some significant deficiencies. Among them:

  1. It will often require the event publisher to perform a linear search to locate the record which contains information related to the subscription. If there's a possibility of an event having many subscribers, this could create O(N^2) behavior needlessly. If subscribers are kept in some kind of linked list (either linked objects or index-linked array slots) and the unsubscribe request holds information about the subscription to be canceled, subscriptions and unsubscriptions can both handled in constant time. Further, unsubscription can be handled safely and easily in lock-free non-blocking fashion (using one `CompareExchange` on what will most likely be an uncontested array slot) that can safely be done in a `Finalize` context.
  2. If one delegate gets subscribed multiple times to an event where the order of processing matters, and code tries to cancel the first subscription, the last subscription will get canceled and the first one will remain in effect.
  3. If a delegate `D` is subscribed, a multicast delegate `ABCD` containing `A`, `B`, `C`, and `D` is subscribed, and then `D` is unsubscribed, then delegates `DABC` will remain subscribed, in the order, even if code tries to unsubscribe `ABCD`. Note that one could avoid this problem if one used a `List` instead of `delegateType.Combine`, but the other issues would remain.

Having the event subscription method return an object that can be used to cancel the subscription avoids these problems. The biggest question then becomes what type of object should be used. Three choices come to mind:

  1. A delegate (probably parameterless, returning `void`)
  2. Some `ICancelSubscription` interface, with a single method (probably parameterless, returning `void`) to cancel the subscription
  3. `IDisposable`, an interface which exists, has a single parameterless method, and is widely used for cleanup-related purposes

Using a delegate would be a reasonable choice. It could be easily encapsulate whatever information was necessary to cancel a subscription without the user having to worry about what form that information might take. Using a delegate would entail the allocation of at least one extra heap object (for the delegate itself) and possibly two (the second being an object holding the unsubscription information). Using IDisposable would be essentially the same as using a delegate, except that one would call Dispose rather than Invoke; in many cases, though, IDisposable would have a slight advantage in terms of efficiency. Using some other interface would also be workable, but wouldn't really offer any advantage over using the existing IDisposable.

like image 72
supercat Avatar answered Oct 20 '22 10:10

supercat