Observer in .NET 4.0 with IObserver(T)

The IObservable(T) and IObserver(T) interfaces are part of base class library of .NET 4.0. It’s great that there is now a out of the box solution to implement the observer pattern. This was overdue, because other languages provides classes to implement this pattern already a long time. It is one of the most used and normally part of every good software design.

The observer pattern contains a class (normally the observable itself) maintains a list of its dependants (the observers) and notifies them automatically of changes. With interfaces (one for the observer and one for the observable), like IObservable(T) and IObserver(T), it is possible to implement the pattern, so the observable doesn’t really know from which classes it will be observed. The interfaces are in the system namespace and look as follows. 

namespace System
{
public interface IObservable
{
IDisposable Subscribe(IObserver observer);
}

public interface IObserver
{
void OnCompleted();
void OnError(Exception error);
void OnNext(T value);
}
}

The observable must implement the subscribe method where observers can be attached. It returns a object of the type IDisposable which can be used to unsubscribe by calling Dispose. The observer has to implement three methods, OnCompleted which is called to indicate that the observable has finished sending notifications, OnError when a error occurred, and OnNext when new data is available (the method is also called update in other languages).

I will show in a simple example how it works. But first we need a base class for all observables which separates the specific code from the standard observable code. This is something which isn’t part of the base class library. Normally a observable can be implemented without any additional code (only the method call which indicates a change). The following code shows a simple generic approach for such a observable base class.

public class Observable<T>: IObservable<T>
{
private List<IObserver<T>> observers;

public Observable()
{
observers = new List<IObserver<T>>();
}

protected void Notify(T obj)
{
foreach (IObserver<T> observer in observers)
{
observer.OnNext(obj);
}
}

public IDisposable Subscribe(IObserver<T> observer)
{
if (!observers.Contains(observer))
{
observers.Add(observer);
}

return new Unsubscriber(observers, observer);
}

private class Unsubscriber : IDisposable
{
private List<IObserver<T>> observers;
private IObserver<T> observer;

public Unsubscriber(List<IObserver<T>> observers, IObserver<T> observer)
{
this.observers = observers;
this.observer = observer;
}

public void Dispose()
{
if (observer != null && observers.Contains(observer))
{
observers.Remove(observer);
}
}
}
}

It already implements the IObservable(T) and so contains the subscribe method. It returns a instance of the Unsubscriber class, which is a simple inner class that implements the IDisposable interface. Also there is a method, which can be called to notify all observers that there are changes in the observed object. As a example we use a class which represents a location, which inherits from the Observable class.

public class Location : Observable<Location>
{
private double longitude = 0 ;
private double latitude = 0;

public double Longitude
{
get { return longitude; }
set
{
longitude = value;
Notify(this);
}
}

public double Latitude
{
get { return latitude; }
set
{
latitude = value;
Notify(this);
}
}
}

With the base class, the concrete observable has only to call Notify. The whole code which is in the base class can also be in the observable (in this case the Location class) itself, for example when you already inherit from another class. The observer tracks the location and displays it when it changes.

public class Tracker : IObserver<Location>
{
public void OnCompleted()
{
Console.WriteLine("untracked");
}

public void OnError(Exception error)
{
//some error handling
}

public void OnNext(Location value)
{
Console.WriteLine("Longitude: "+ value.Latitude.ToString()+" "+
"Latitude: "+ value.Longitude.ToString());
}
}

The OnNext method writes the location into the console. The following code can be used to execute the example.

class Program
{
static void Main(string[] args)
{
var location = new Location();
var tracker = new Tracker();
var unsubscriber = location.Subscribe(tracker);

double latitude = 37.44;
double longitude = -122.14;

for(int i = 0 ; i < 100 ; i++)
{
Thread.Sleep(100);
latitude -= 0.1;
longitude += 0.1;

location.Latitude = latitude;
location.Longitude = longitude;

}

unsubscriber.Dispose();
}
}

So these two interfaces, IObservable(T) and IObserver(T), give you the ability to implement the pattern. For me, the naming of the methods is a little bit different than expected and also the concept of unsubscription is a confusing at the beginning. Also a little bit disappointing is that a base class for the observable is missing.  But after all they did a good job providing a standardized way.

49 thoughts on “Observer in .NET 4.0 with IObserver(T)

  1. .NET already had an implementation of the observer pattern — CLR events and event handlers — which are still fine for 99% of situations. The new interfaces are for push-based event sequences e.g. Rx.

  2. You have several possibilities to implement a ovbserver pattern. The IObserver(T) provides you just another way you can do it. But the important thing is, it is a implementation which everyone recognize and so results in a better maintainability.

  3. Or, re-written slightly:

    var location = new Location();
    var tracker = new Tracker();

    using (location.Subscribe(tracker)) {

    double latitude = 37.44;
    double longitude = -122.14;

    for(int i = 0 ; i < 100 ; i++)
    {
    Thread.Sleep(100);
    latitude -= 0.1;
    longitude += 0.1;
    location.Latitude = latitude;
    location.Longitude = longitude;
    }
    }

  4. Richard – you can do push based events without IObservable using the custom event arguments and the generic EventHandler<T> class

  5. This is this kind of an excellent resource which you are providing and you give it away for free. I love seeing websites that understand the value of providing a quality resource for free. It?s the old what goes around comes close to routine. Did you acquired plenty of links and I see lots of trackbacks?

Comments are closed.