简体   繁体   中英

How do I set an Observable to watch a Property?

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?

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. Eg

//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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM