将最后一项推到Observable(序列)

时间:2017-02-04 16:08:02

标签: c# .net system.reactive rx.net

我在类中有一个IObservable<Item>,我希望公开一个只读属性,该属性提供在给定时间推送到observable的最后一项。因此它将提供Item的单个值。

如果没有推送任何值,则必须返回默认值。

如何在不订阅observable并拥有“支持字段”的情况下执行此操作?

3 个答案:

答案 0 :(得分:4)

只是为了补充@阿斯蒂的答案,或许可以帮助你解决挫折感:

一个可观察的事物并不是一个物质的东西,它更像是一个逻辑概念。 Rx经常与LINQ进行比较,并且它在很多时候都是公平的比较。当你开始讨论数据结构时,它会崩溃:LINQ的可枚举类似于列表用于学习目的。

然而,在Rx方面,它与List没有任何好处。可观察的是瞬态数据结构,所有运算符都处理这种瞬态。如果您正在寻找永久性州,那么您将离开Rx。

话虽如此,将一个observable转换为某种状态是一个常见的问题,并且有一些软件包可以帮助你:ReactiveUI可能是最知名的。 ReactiveProperty是另一个。这两个软件包都存在缺陷,但可能对您有所帮助。

如果您只是寻找一种更简单的方法来获得支持领域,而不需要在支持领域进行电镀,那么这将有效:

public static class ReactivePropertyExtensions
{
    public static ReactiveProperty<T> ToReactiveProperty<T>(this IObservable<T> source)
    {
        return new ReactiveProperty<T>(source);
    }

    public static ReactiveProperty<T> ToReactiveProperty<T>(this IObservable<T> source, T defaultValue)
    {
        return new ReactiveProperty<T>(source, defaultValue);
    }
}

public class ReactiveProperty<T> : IDisposable
{
    private IObservable<T> Source { get; }
    private IDisposable Subscription { get; }
    public T Value { get; private set; }

    public ReactiveProperty(IObservable<T> source)
        : this(source, default(T)) { }

    public ReactiveProperty(IObservable<T> source, T defaultValue)
    {
        Value = defaultValue;
        Source = source;
        Subscription = source.Subscribe(t => Value = t);
    }

    public void Dispose()
    {
        Subscription.Dispose();
    }
}

使用示例:

var ticker = Observable.Interval(TimeSpan.FromSeconds(1))
    .Publish().RefCount();

var latestTickerValue = ticker.ToReactiveProperty();
Console.WriteLine(latestTickerValue.Value);
await Task.Delay(TimeSpan.FromSeconds(1));
Console.WriteLine(latestTickerValue.Value);
await Task.Delay(TimeSpan.FromSeconds(3));
Console.WriteLine(latestTickerValue.Value);

答案 1 :(得分:2)

假设热观察。

observable = source.Replay(1); observable.Connect();

提供以下值:

public int Value => observable.Take(1).Amb(Observable.Return(defaultValue)).Wait();

如果没有按下任何值,这将返回默认值。

您希望从Reactive转换为State,因此支持字段不是一个糟糕的选择。你提到你不想订阅,但要观察任何事情:某事,某处必须订阅

答案 2 :(得分:1)

这是本着Asti solution的精神来定义Value属性的另一种方法。

private readonly IObservable<Item> _source;
private readonly IObservable<Item> _lastValue;

public SomeClass() // Constructor
{
    _source = /* Initialize the source observable (hot) */

    _lastValue = _source
        .Catch(Observable.Never<Item>())
        .Concat(Observable.Never<Item>())
        .Multicast(new BehaviorSubject<Item>(default))
        .AutoConnect(0)
        .FirstAsync();
}

public Item Value => _lastValue.Wait();

BehaviorSubject<T>是专门的ISubject<T>,......

表示随时间变化的值。观察者可以订阅主题以接收最后(或初始)值以及所有后续通知。

添加了CatchConcat运算符以保留最后一个值,即使源序列正常或异常完成。

我个人会犹豫使用此解决方案,因为在volatile运算符中更新的Do字段会更自然地完成相同的事情。我主要将其发布为Rx功能的演示。