【问题标题】:"Neverending" TakeWhile, BufferWhile and SkipWhile RX.Net Sequences“永无止境”的 TakeWhile、BufferWhile 和 SkipWhile RX.Net 序列
【发布时间】:2015-11-10 11:31:20
【问题描述】:

我想知道是否有办法获取可观察流并使用 *While 运算符,特别是 TakeWhile、SkipWhile 和 BufferWhile,以便它们的订阅者在 bool 'while' 条件被满足时不会收到 .OnComplete ?

当我开始使用 .TakeWhile / SkipWhile 和 BufferWhile 运算符时,我假设它们不会终止 / .OnComplete() 而只是(不)在满足 bool 条件时发出。

举个例子可能更有意义:

我有一个 bool 标志,用于指示实例是否忙,以及一个 Observable 数据流:

private bool IsBusy { get;set; }
private bool IgnoreChanges { get;set; }

private IObservable<int> Producer { get;set; }
private IDisposable ConsumerSubscription { get;set; }

.. 并像这样使用/设置 RX 流(简化)

private void SetupRx()
{
    ConsumerSubscription = Producer
        .SkipWhile(_ => IgnoreChanges == true) // Drop the producer's stream of ints whenever the IgnoreChanges flag is set to true, but forward them whenever the IgnoreChanges flag is set to false
        .BufferWhile(_ => IsBusy == true) // for all streamed instances buffer them as long as we are busy handling the previous one(s)
        .Subscribe(i => DoSomething(i));
}

private void DoSomething(int i)
{
    try
    {
        IsBusy = true;
        // ... do something
    }
    finally
    {
        IsBusy = false;
    }
}

当 IsBusy/IgnoreChanges 标志从 true 切换到 false 并返回时,.SkipeWhile/.BufferWhile 不应该完成/OnComplete(..),但要保持流处于活动状态。

开箱即用的 RX.Net 是否可行和/或有人知道如何做到这一点?

【问题讨论】:

  • 澄清一下,RX.net 中没有 BufferWhile(我的错误)

标签: .net system.reactive reactive-programming


【解决方案1】:

要从IObservable&lt;T&gt; 源中删除OnCompleted 消息,只需将ConcatObservable.Never&lt;T&gt;() 结合使用:

source.TakeWhile(condition).Concat(Observable.Never<T>())

要手动订阅IObservable&lt;T&gt; 源以便仅在您手动取消订阅时结束订阅,您可以使用PublishIConnectableObservable&lt;T&gt;

var connectableSource = source.Publish();
// To subscribe to the source:
var subscription = connectableSource.Connect();
...
// To unsubscribe from the source:
subscription.Dispose();

说了这么多,我认为您的处理方法不正确。如果正确完成,您将不需要上述技巧。查看您的查询:

ConsumerSubscription = Producer
    // Drop the producer's stream of ints whenever the IgnoreChanges flag
    // is set to true, but forward them whenever the IgnoreChanges flag is set to false
    .SkipWhile(_ => IgnoreChanges == true) 
    // For all streamed instances buffer them as long as we are busy
    // handling the previous one(s)
    .BufferWhile(_ => IsBusy == true) 
    .Subscribe(i => DoSomething(i));

您应该使用.Where(_ =&gt; !IgnoreChanges) 而不是.SkipWhile(_ =&gt; IgnoreChanges)

您应该使用.Buffer(_ =&gt; IsBusy.SkipWhile(busy =&gt; busy))BehaviorSubject&lt;bool&gt; IsBusy 而不是.BufferWhile(_ =&gt; IsBusy)

完整的代码如下所示:

private BehaviorSubject<bool> IsBusy { get;set; }
private bool IgnoreChanges { get;set; }

private IObservable<int> Producer { get;set; }
private IDisposable ConsumerSubscription { get;set; }

private void SetupRx()
{
    ConsumerSubscription = Producer
        .Where(_ => !IgnoreChanges)
        .Buffer(_ => IsBusy.SkipWhile(busy => busy))
        .Subscribe(buffer => DoSomething(buffer));
}

private void DoSomething(IList<int> buffer)
{
    try
    {
        IsBusy.OnNext(true);
        // Do something
    }
    finally
    {
        IsBusy.OnNext(false);
    }
}

下一个改进是尝试摆脱BehaviorSubject&lt;bool&gt; IsBusy。主题是您要尽量避免的事情,因为它们是您必须管理的状态。

【讨论】:

  • 感谢蒂莫西关于简化我的想法的提示!我注意到 RX 中根本没有 BufferWhile,所以我稍微摆弄了一下,并为我的三个用例编写了三个扩展方法:github.com/jbattermann/JB.Common/blob/master/JB.Common.Reactive/… ... SkipWhile/TakeWhile 实际上很容易编写,但不太满意(我的).BufferWhile 还没有,但是哦,好吧.. 但总的来说 - 感谢您对 Publish、Where 等的回复和澄清/指示。干杯!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多