Say I want to generate an asynchronous stream of random numbers that pumps out a new value every 100 milliseconds. While trying to come up with a solution, my first attempt looked something like this:
var random = new Random();
Observable.Start(() => random.Next())
.Delay(TimeSpan.FromMilliseconds(100))
.Repeat()
.Subscribe(Console.WriteLine);
If you try and run this, you'll notice that it just keeps repeating the same value over and over again. OK, I guess I misunderstood how Repeat works. After playing around for a bit, I came up with this and it worked:
var random = new Random();
Observable.Defer(()=> Observable.Start(() => random.Next()))
.Delay(TimeSpan.FromMilliseconds(100))
.Repeat()
.Subscribe(Console.WriteLine);
So I went to the MSDN documentation to understand what Defer is actually doing, and this is what it says:
Returns an observable sequence that invokes the observable factory whenever a new observer subscribes.
I guess my confusion is this: in my code sample, I'm only ever subscribing to the Observable once, so why is it seemingly invoking the Observable.Start(...)
over and over? Or am I misunderstanding Repeat()
? Any clarification would be awesome.
You are misunderstanding Repeat. Basically, Repeat will keep resubscribing to an observable every time it is completed.
Observable.Start apparently caches the value the first time you call Subscribe and is returning it each time you subscribe. This is what causes the same number over and over in the first example.
Defer works something like this:
IObservable<T> Defer(Func<IObservable<T>> factory)
{
return Observable.Create<T>(obs => factory().Subscribe(obs));
}
so every time you subscribe to the Defer
observable, it must call the factory
function. In this case, the factory creates a new observable, thus avoiding the caching behavior of Start
.
An alternate way to get the sequence you described is to use Interval
to get your timing and Select
to get the random numbers.
Observable.Interval(TimeSpan.FromMilliseconds(100))
.Select(i => random.Next())
.Subscribe(Console.WriteLine);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With