views:

322

answers:

3

Let's say, we have a class:

public class Foo
{
   public string Do(int param)
   {
   }
}

I'd like to create an observable of values that are being produced by Do method. One way to do it would be to create an event which is being called from Do and use Observable.FromEvent to create the observable. But somehow I don't feel good about creation of an event just for the sake of the task. Is there a better way to do it?

+1  A: 

I'm assuming you control the Foo class, since you're talking about adding an event to it as one option. Since you own the class, is there any reason you can't define your own IObservable implementation for the Do method?

public class Foo
{
    DoObservable _doValues = new DoObservable();

    public IObservable<String> DoValues
    {
        return _doValues;
    }

    public string Do(int param)
    {
        string result;
        // whatever
        _doValues.Notify(result);
    }
}

public class DoObservable : IObservable<String>
{
    List<IObserver<String>> _observers = new List<IObserver<String>>();

    public void Notify(string s)
    {
        foreach (var obs in _observers) obs.OnNext(s);
    }

    public IObserver<String> Subscribe(IObserver<String> observer)
    {
        _observers.Add(observer);
        return observer;
    }
}

Your class now has an Observable<String> property which provides a way to subscribe to the values returned from the Do method:

public class StringWriter : IObserver<String>
{
    public void OnNext(string value)
    {
        Console.WriteLine("Do returned " + value);
    }

    // and the other IObserver<String> methods
}

var subscriber = myFooInstance.DoValues.Subscribe(new StringWriter());
// from now on, anytime myFooInstance.Do() is called, the value it 
// returns will be written to the console by the StringWriter observer.

I've not dabbled too much into the reactive framework, but I think this is close to how you would do this.

Matt Hamilton
You can make your DoObserver class an inner (nested) class of the Foo class, too, to keep it as a closed system.
Matt Hamilton
Also see http://stackoverflow.com/questions/1768974/implementing-iobservablet-from-scratch, which has a more complete implementation including supporting unsubscribing via IDisposable.
Matt Hamilton
+1  A: 

Matt's answer made me thinking about this:

public class Foo
{
    private readonly Subject<string> _doValues = new Subject<string>();

    public IObservable<string> DoValues { get { return _doValues; } }

    public string Do(int param)
    {
        var ret = (param * 2).ToString();
        _doValues.OnNext(ret);
        return ret;
    }
}


var foo = new Foo();
foo.DoValues.Subscribe(Console.WriteLine);
foo.Do(2);
Sergey Aldoukhov
A: 

I would look at the EventAggregator model. There's a great article with sample code that shows an implementation with StructureMap.

http://www.codeproject.com/KB/architecture/event_aggregator.aspx

Corey Coogan
My question was specifically on how to most efficiently accomplish the task using the RX extensions. The link you provided is not related to RX.
Sergey Aldoukhov
Sorry for the confusion here, but the question is "What is a good way to create an IObservable for a method?". Where does it say anything about RX Extensions? EventAggregator is a decoupled form of achieving the Observer Pattern. Still worth a look in my opinion.
Corey Coogan
There is a context that points to RX - the tag, the reference to an existing solution of using Observable.FromEvent. Anyway, from now on the only "real" IObservable is the one that comes from System.Reactive namespace.
Sergey Aldoukhov