Observable.Defer - нужно уточнить, что именно он делает
Скажем, я хочу создать асинхронный поток случайных чисел, который выкачивает новое значение каждые 100 миллисекунд. Пытаясь придумать решение, моя первая попытка выглядела примерно так:
var random = new Random();
Observable.Start(() => random.Next())
.Delay(TimeSpan.FromMilliseconds(100))
.Repeat()
.Subscribe(Console.WriteLine);
Если вы попытаетесь запустить это, вы заметите, что он постоянно повторяет одно и то же значение снова и снова. Хорошо, я думаю, я неправильно понял, как работает Repeat. Поиграв немного, я придумал это, и это сработало:
var random = new Random();
Observable.Defer(()=> Observable.Start(() => random.Next()))
.Delay(TimeSpan.FromMilliseconds(100))
.Repeat()
.Subscribe(Console.WriteLine);
Итак, я пошел в документацию MSDN, чтобы понять, что делает Дефер, и вот что он говорит:
Возвращает наблюдаемую последовательность, которая вызывает наблюдаемый factoryкаждый раз, когда подписывается новый наблюдатель.
Я предполагаю, что моя путаница такова: в моем примере кода я только когда-либо подписываюсь на Observable один раз, так почему это, похоже, снова и снова вызывает Observable.Start(...)
? Или я недопонимаю Repeat()
? Любое уточнение было бы удивительным.
Ответы
Ответ 1
Вы недопонимаете повторение. В принципе, Repeat будет сохранять повторную подписку на наблюдаемую при каждом ее завершении.
Observable.Start, по-видимому, кэширует значение при первом вызове Subscribe и возвращает его каждый раз, когда вы подписываетесь. Это то, что вызывает одно и то же число снова и снова в первом примере.
Defer работает примерно так:
IObservable<T> Defer(Func<IObservable<T>> factory)
{
return Observable.Create<T>(obs => factory().Subscribe(obs));
}
поэтому каждый раз, когда вы подписываетесь на наблюдаемый Defer
, он должен вызывать функцию factory
. В этом случае factory создает новый наблюдаемый, что позволяет избежать поведения кэширования Start
.
Альтернативный способ получить описанную вами последовательность - использовать Interval
для получения времени и Select
для получения случайных чисел.
Observable.Interval(TimeSpan.FromMilliseconds(100))
.Select(i => random.Next())
.Subscribe(Console.WriteLine);
Ответ 2
Простым способом "генерации" случайных чисел является использование .Generate
. Попробуйте следующее:
var rnd = new Random();
Observable
.Generate(
0,
x => true,
x => x,
x => rnd.Next(),
x => TimeSpan.FromMilliseconds(100.0))
.Subscribe(n => { });