Подтвердить что ты не робот

Объединение булевых наблюдений

У меня есть два потока, сигнализирующие о смене условий. Мне нужен Observable, который будет стрелять true, когда все условия повернутся true. false, когда любой из них поворачивается false. Если некоторые из условий false, а другое изменяется на false, мне не нужно поднимать события.

Вот как я это делаю:

// 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 /*);
    // ...
}

Я хочу знать, правильно ли это решить мою проблему, и если есть какие-то ошибки. Например, c3 подписывает огонь перед c1 и c2 из-за асинхронного характера rx.

4b9b3361

Ответ 1

Не нужно сохранять состояние:

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

Ответ 2

Честно говоря, я бы, вероятно, пошел с подходом CombineLatest, но в интересах прикосновения к несколько нетронутым частям рамки Rx...

Хотя это не идеально подходит, вы можете использовать шаблон Observable.When/Observable.And/Observable.Then:

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();
}

Одно из преимуществ этого подхода заключается в том, что вы создаете выходные события, когда все потоки имеют данные, которые объединяются в соответствии с предложением Then - он также читается довольно красиво. Тем не менее, у него есть один критический провал для вашего случая использования: у вас должны быть данные по каждому входящему потоку для запуска выходного потока:

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();
}

Ответ 3

Как и JerKimball, я собирался предложить использовать Joins (now When):

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();

Это немного запутано, когда есть много Observables.