【问题标题】:Combining boolean Observables组合布尔 Observables
【发布时间】:2013-03-01 12:45:28
【问题描述】:

当某些条件发生变化时,我有两个流信号。我需要一个 Observable,它会在 所有条件 变为 true 时触发 truefalse其中任何一个变成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 /*);
    // ...
}

我想知道这是否是解决我的问题的正确方法以及是否有任何陷阱。例如,由于 rx 的异步特性,c3 订阅在 c1 和 c2 之前触发。

【问题讨论】:

    标签: c# boolean system.reactive


    【解决方案1】:

    不需要保持状态:

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

    【讨论】:

    • Humbug - 我已经查看 API 很久了,但没有找到!但是,您可能也想要DistinctUntilChanged
    • My go-to RX API reference - CombineLatest 示例就是这个确切的问题 (!)
    • 我认为这不完全符合要求。只有当所有值都为假时,序列才会产生假值,否则保持沉默。如果所有值都为真,则推送一个真值。如果任何值为 false,此解决方案将推送 false。
    • DistinctUntilChanged() 应该符合要求 - 我已经编辑了答案以使其更明确(尽管我最初提到过)
    • 我认为这仍然不对。 c1.OnNext(假);c2.OnNext(真);这将结合 false&&true->false。即不正确地产生假,不管 DistinctUntilChanged();
    【解决方案2】:

    像 JerKimball 一样,我打算建议使用 Joins(现在何时):

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

    但是,当有很多 Observable 时,它​​确实会变得有点混乱。

    【讨论】:

    • 很好 - 确实,它确实会变得混乱,但如果你像在此处所做的那样将其拆分为单独的 Plan 语句,则实际上可以通过循环构造“构建”查询。 :)
    【解决方案3】:

    老实说,我可能会采用 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();
    }
    

    【讨论】:

    • :) 我打算这样做...不适合...我会添加一个答案。
    猜你喜欢
    • 2017-08-18
    • 2016-12-22
    • 2013-01-07
    • 1970-01-01
    • 1970-01-01
    • 2018-10-19
    • 2018-04-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多