“无休止”TakeWhile,BufferWhile和SkipWhile RX.Net序列

时间:2015-11-10 11:31:21

标签: .net system.reactive reactive-programming

我想知道是否有办法采用可观察的流并使用* 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在某种程度上是可行的和/或有人知道如何实现这个目标吗?

1 个答案:

答案 0 :(得分:5)

要从OnCompleted来源中删除IObservable<T>消息,只需Concat Observable.Never<T>()

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

要手动订阅IObservable<T>来源,只有在您手动取消订阅时订阅才会结束,您可以使用PublishIConnectableObservable<T>

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(_ => !IgnoreChanges)代替.SkipWhile(_ => IgnoreChanges)

您应该.Buffer(_ => IsBusy.SkipWhile(busy => busy))使用BehaviorSubject<bool> IsBusy代替.BufferWhile(_ => 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<bool> IsBusy。主题是你想要避免的东西,因为它们是你必须管理的状态。