How do I set an Observable to watch a Property?

Viewed 3586

I realize this is probably a very stupid question but the documentation on Reactive Extensions is both opaque and scattered.

Suppose I have a class

public class Foo
{
    public int FooState {get;set;}
}

and FooState is updated very frequently. This looks like an ideal case for an IObservable, especially since I'll have to track that state in another class.

public class Bar
{
    public Foo Foo {get;set;}

    private void DoStuffWithFooState()
    {
        //operate on Foo.FooState here
    }
}

Now, I can't change FooState into an IObservable<int> because that would break other stuff that relies on Foo.

What I'd like to do is is declare an IObserver property on Bar that watches FooState.

Isn't this a basic use case? How do I go about it?

1 Answers

You can use a BehaviorSubject to allow you to turn the property into both an observable stream and a property from which you can just read the latest value.

public class Foo
{
    private readonly BehaviorSubject<int> _fooSubject = new BehaviorSubject<int>(0);
    public int FooState
    {
        get => _fooSubject.Value;
        set => _fooSubject.OnNext(value);
    }
    public IObservable<int> ObservableFooState => _fooSubject;
}

If the value of FooState is changing frequently then you'll probably want to use the Sample operator prior to subscription. E.g.

//print out value every two seconds
foo.ObservableFooState
   .Sample(TimeSpan.FromSeconds(2)) 
   .Subscribe(Console.WriteLine);

Note that a common mistake is to use Throttle and then wonder why you hardly ever get any events! (The reason is that Throttle resets the timeout every time a new event arrives so when the stream is updated frequently you'll never exceed the timeout value.)

Although it's old and slightly outdated in parts, I find this guide to be very useful when trying to learn about Reactive. The Rx HOL is even older and even more outdated but still a very useful conceptual introduction - just don't take the code samples too literally.

If this class is actually a ViewModel, you might want to consider ReactiveUI but I would suggest steering away from that until you are really comfortable with Reactive.

Note that I haven't shown Dispose/Completion logic above. You should consider when (if ever) you want to call OnCompleted on _fooSubject. Also bear in mind that subscriptions are disposable and you probably want to ensure you dispose of them when your subscribers go out of scope.

Related