Friday, December 23, 2011

IDisposable implementations in Reactive Extensions

System.Reactive.Disposable namespace contains several implementations of the IDisposable interface in conjunction with RX.
public interface IDisposable
{
    void Dispose();
}
The main reason for the existence of these classes is that they can be used in your implementations of the observable's Subscribe method which returns an IDisposable.
public interface IObservable<out T>
{
    IDisposable Subscribe(IObserver<T> observer);
}
For example you can return an Empty disposable which actually does nothing:
var source = Observable.Create<int>(
    observer => {
        observer.OnNext(1);
        return Disposable.Empty;
    }
);
Or you can use the static Disposable.Create method and provide it with an action which will be called during disposal:
var source = Observable.Create<int>(
    observer => {
        observer.OnNext(1);
        return Disposable.Create(() => "Dispose".Dump());
    }
);

using (source.Subscribe(v => v.Dump()))
{
}
================
1
Dispose
================
In the following example we will return instead of an IDisposable an action which will be wrapped to an IDisposable:
var source = Observable.Create<int>(
    observer => {
        observer.OnNext(1);
        return () => "Dispose".Dump();
    }
);
A BooleanDisposable will change it's IsDisposed property to false after disposal:
var booleanDisposable = new BooleanDisposable();
if (!booleanDisposable.IsDisposed)
{
    booleanDisposable.Dispose();
}
The SingleAssignmentDisposable's Disposable property can be set only ones as the name suggest, for the second attempt it will raise an InvalidOperationException with the message "Disposable has already been assigned.". You can use it in two different ways. You can first assign your IDisposable to the Disposable property and then dispose the SingleAssignmentDisposable:
var sad = new SingleAssignmentDisposable();

sad.Disposable = 
    Disposable.Create(() => "Single disposed".Dump()); 
    
sad.Dispose();
================
Single disposed
================
Or you can first dispose the SingleAssignmentDisposable and then assign your IDisposable to it. In this case your IDisposable will be automatically disposed during the assignment to the Disposable property:
var sad = new SingleAssignmentDisposable();

sad.Dispose();

sad.Disposable = 
    Disposable.Create(() => "Single disposed".Dump()); 
================
Single disposed
================
SerialDisposable allows you to set multiple times the Disposable property. In that case the current Disposable will be disposed and then change to the new one.
var serialDisposable = new SerialDisposable();
serialDisposable.Disposable = Disposable.Create(() => "Disposed 1".Dump());
"Set a new disposable.".Dump();
serialDisposable.Disposable = Disposable.Create(() => "Disposed 2".Dump());
"Call serial disposable's dispose.".Dump();
serialDisposable.Dispose();
================
Set a new disposable.
Disposed 1
Call serial disposable dispose.
Disposed 2
================
In case that you want to dispose multiple disposables at once you can use the CompositeDisposable class which implements the ICollection<T> interface:
IDisposable disposable1 = 
            Observable.Return(1)
            .Subscribe(Console.WriteLine);
                            
IDisposable disposable2 = 
            Observable.Return(2)
            .Subscribe(Console.WriteLine);
                            
using(new CompositeDisposable(disposable1, disposable2))
{
};
================
1
2
================
or
IDisposable disposable1 = Disposable.Create(() => "Disposed 1".Dump());
IDisposable disposable2 = Disposable.Create(() => "Disposed 2".Dump());
IDisposable disposable3 = Disposable.Create(() => "Disposed 3".Dump());
var compositeDisposable = new CompositeDisposable()
    {
        disposable1,
        disposable2
    };
compositeDisposable.Add(disposable3);
compositeDisposable.Dispose();
================
Disposed 1
Disposed 2
Disposed 3
================
The final example will use a CancellationDisposable which is disposed when you call the Cancel method on the injected CancellationTokenSource:
var cts = new CancellationTokenSource();

var cd = new CancellationDisposable(cts);

cts.Cancel();

cd.IsDisposed.Dump();
================
True
================
There are also other implementations of the IDisposable interface in this namespace such as MultipleAssignmentDisposable, SchedulerDisposable and so on, but I'm not going to cover these in this topic.

No comments:

Post a Comment