我在类中有一个IObservable<Item>
,我希望公开一个只读属性,该属性提供在给定时间推送到observable的最后一项。因此它将提供Item
的单个值。
如果没有推送任何值,则必须返回默认值。
如何在不订阅observable并拥有“支持字段”的情况下执行此操作?
答案 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>
,......
表示随时间变化的值。观察者可以订阅主题以接收最后(或初始)值以及所有后续通知。
添加了Catch
和Concat
运算符以保留最后一个值,即使源序列正常或异常完成。
我个人会犹豫使用此解决方案,因为在volatile
运算符中更新的Do
字段会更自然地完成相同的事情。我主要将其发布为Rx功能的演示。