2013-03-13 16 views
11

Mam dwa strumienie sygnalizujące, gdy niektóre warunki ulegną zmianie. Muszę obserwowanej który będzie ogień true gdy wszystkie warunki włączyć true. false, gdy którykolwiek z nich zamienia się na . Jeśli niektóre warunki to false, a kolejne zmiany to false, nie muszę zgłaszać zdarzeń.Łączenie obserwowalnych obiektów logicznych

Oto jak ja to robię:

// Introducing current states 
private bool cond1 = false; 
private bool cond2 = false; 

void MyHandlingMethod(IObservable<bool> c1, IObservable<bool> c2) 
{ 
    c1.Subscribe(b => _state1 = b); 
    c2.Subscribe(b => _state2 = b); 

    var c3 = c1.Merge(c2).Select(_ => _cond1 && _cond2); 

    c3.Subscribe(b => /* some action goes here /*); 
    // ... 
} 

Chcę wiedzieć, czy jest to właściwy sposób rozwiązać mój problem i czy są jakieś pitfals. Np. Subskrypcja c3 uruchamia się przed c1 i c2 z powodu asynchronicznej natury rx.

Odpowiedz

11

Nie ma potrzeby, aby utrzymać stan:

c3 = c1.CombineLatest(c2, (a, b) => a && b).DistinctUntilChanged() 
+1

Humbug - Przeglądam API przez wieki i nie udało mi się tego znaleźć! Prawdopodobnie jednak chcesz również "DistinctUntilChanged". –

+0

[My go-RX odniesienia API] (http://www.introtorx.com/content/v1.0.10621.0/12_CombiningSequences.html) - w CombineLatest przykładem jest dokładny to pytanie – AlexFoxGill

+0

nie sądzę, to całkowicie (!) spełnia wymagania. Tylko jeśli wszystkie wartości są fałszywe, jeśli sekwencja daje wartość false, inaczej milczy. Jeśli wszystkie wartości są prawdziwe, naciśnij prawdę. Ten soln będzie wypychał fałsz, jeśli dowolna wartość jest fałszywa. –

2

Szczerze, to bym pewnie iść z podejściem CombineLatest, ale w interesie dotykania nieco-nietknięte części ramy Rx ...

Chociaż nie jest to idealne dopasowanie, można użyć Observable.When/Observable.And/Observable.Then wzór:

var firstStream = new Subject<bool>(); 
var secondStream = new Subject<bool>(); 
var thirdStream = new Subject<bool>(); 
var fourthStream = new Subject<bool>(); 

var query = Observable.When(firstStream 
     .And(secondStream) 
     .And(thirdStream) 
     .And(fourthStream) 
     .Then((v1,v2,v3,v4) => v1 & v2 & v3 & v4)); 

using(query.Subscribe(Console.WriteLine)) 
{ 
    firstStream.OnNext(true); 
    secondStream.OnNext(true); 
    thirdStream.OnNext(true); 
    // output stream will fire after this statement 
    fourthStream.OnNext(true); 
    Console.ReadLine(); 
} 

Jedną z zalet tego podejścia jest tworzenie zdarzeń wyjściowych tylko wtedy, gdy wszystkie strumienie mają dane, które łączą się zgodnie z klauzulą ​​Then - czyta się też dość ładnie. Powiedział, że ma jedną krytyczną uszkodzoną przypadku użycia: ty musi posiada dane dotyczące każdego strumienia wchodzącego do uruchomienia strumienia wyjściowego:

using(query.Subscribe(Console.WriteLine)) 
{ 
    firstStream.OnNext(true); 
    secondStream.OnNext(true); 
    thirdStream.OnNext(true); 
    // output stream will fire after this statement 
    fourthStream.OnNext(true); 

    // this WON'T raise false on the output! 
    firstStream.OnNext(false); 
    secondStream.OnNext(false); 
    thirdStream.OnNext(false); 
    // output stream will fire false after this statement 
    fourthStream.OnNext(false); 
    Console.ReadLine(); 
} 
+0

:) Chciałem to zrobić tak ... nie pasuje ... Dodam odpowiedź. –

0

Jak JerKimball, miałem zamiar zaproponować za pomocą połączeń (teraz kiedy) :

IObservable<bool> cond1 = new [] { false, true, true, false, false }.ToObservable(); 
IObservable<bool> cond2 = new [] { true, true, false, false, true }.ToObservable(); 
Func<bool, bool> isFalse = (x) => x == false; 
Func<bool, bool> isTrue = (x) => x == true; 
var trueC1s = cond1.Where(isTrue); 
var falseC1s = cond1.Where(isFalse); 
var trueC2s = cond2.Where(isTrue); 
var falseC2s = cond2.Where(isFalse); 
var trues = trueC1s.And(trueC2s).Then((_, __) => true); 
var falses = trueC1s.And(falseC2s).Then((_, __) => false); 
var falses2 = falseC1s.And(trueC2s).Then((_, __) => false); 
var falses3 = falseC1s.And(falseC2s).Then((_, __) => false); 
Observable.When(trues, falses, falses2, falses3).Dump(); 

Jest jednak trochę niechlujnie, gdy jest wiele obserwatorów.

+0

Nice - prawda, robi się niechlujnie, ale jeśli podzielisz go na indywidualne instrukcje 'Plan', tak jak tutaj, możesz" zbudować "zapytanie za pomocą konstrukcji pętli. :) – JerKimball

+0

@JerKimball True :). –