2012-07-12 30 views
13

Powiedz, że chcę generować asynchroniczny strumień liczb losowych, który wypompowuje nową wartość co 100 milisekund. Starając się wymyślić rozwiązanie, moja pierwsza próba wyglądała mniej więcej tak:Observable.Defer - potrzebuję wyjaśnienia, co dokładnie robi

 var random = new Random(); 
     Observable.Start(() => random.Next()) 
        .Delay(TimeSpan.FromMilliseconds(100)) 
        .Repeat() 
        .Subscribe(Console.WriteLine); 

Jeśli spróbujesz i uruchomić to zauważysz, że po prostu powtarza tę samą wartość w kółko. OK, chyba źle zrozumiałem, jak działa Powtarzanie. Po zabawy na trochę, wymyśliłem to i to działało:

 var random = new Random(); 
     Observable.Defer(()=> Observable.Start(() => random.Next())) 
        .Delay(TimeSpan.FromMilliseconds(100)) 
        .Repeat() 
        .Subscribe(Console.WriteLine); 

Poszedłem więc do dokumentacji MSDN, aby zrozumieć, co Defer faktycznie robi, a to jest to, co mówi:

Zwraca obserwowalną sekwencję, która wywołuje obserwowalną fabrykę za każdym razem, gdy nowy obserwator subskrybuje.

Chyba mój zamieszanie jest taka: w moim próbki kodu, mam tylko kiedykolwiek subskrypcji raz obserwowalnym, więc dlaczego jest pozornie wywoływanie Observable.Start(...) kółko? Czy nie rozumiem, że jest to Repeat()? Wszelkie wyjaśnienia byłyby niesamowite.

Odpowiedz

17

Nieporozumienie Powtarzaj. Zasadniczo funkcja Powtarzaj będzie ponownie przesyłać subskrypcję do obserwowalnego za każdym razem, gdy zostanie zakończona.

Observable.Start pozornie buforuje wartość przy pierwszym wywołaniu Subskrybcji i zwraca ją za każdym razem, gdy subskrybujesz. To właśnie powoduje ten sam numer w kółko w pierwszym przykładzie.

IObservable<T> Defer(Func<IObservable<T>> factory) 
{ 
    return Observable.Create<T>(obs => factory().Subscribe(obs)); 
} 

więc za każdym razem, gdy subskrybować Defer obserwowalnym, musi wywołać funkcję factory:

Defer coś jak to działa. W takim przypadku fabryka tworzy nowy obiekt new, unikając w ten sposób zachowania buforowania Start.

Alternatywnym sposobem uzyskania opisanej sekwencji jest użycie Interval, aby uzyskać czas i Select, aby uzyskać losowe liczby.

Observable.Interval(TimeSpan.FromMilliseconds(100)) 
      .Select(i => random.Next()) 
      .Subscribe(Console.WriteLine); 
5

Prostym sposobem do „wygenerowania” liczb losowych jest użycie .Generate. Wypróbuj to:

var rnd = new Random(); 

Observable 
    .Generate(
     0, 
     x => true, 
     x => x, 
     x => rnd.Next(), 
     x => TimeSpan.FromMilliseconds(100.0)) 
    .Subscribe(n => { }); 
Powiązane problemy