假设我有一个观察IObservable的对象,以便它始终知道某些外部源的当前状态。在我的对象内部有一个方法,它使用该外部值作为操作的一部分:
public class MyObject
{
public MyObject(IObservable<T> externalSource) { ... }
public void DoSomething()
{
DoSomethingWith(CurrentT);
}
}
使用IObservable“跟踪当前状态”而非“响应事件流”的“自动”反应方式是什么。
想法#1只是监控可观察值并记下它们的值。
public class MyObject
{
private T CurrentT;
public MyObject(IObservable<T> externalSource)
{
externalSource.Subscribe((t) => { CurrentT = t; });
}
public void DoSomething()
{
DoSomethingWith(CurrentT);
}
}
这很好,但跟踪班级成员的状态似乎非常不活跃。
创意#2是使用BehaviorSubject
public class MyObject
{
private readonly BehaviorSubject<T> bs;
public MyObject(BehvaiorSubject<T> externalSource)
{
this.bs = externalSource
}
public void DoSomething()
{
DoSomethingWith(bs.Value);
}
}
但直接使用主题似乎不受欢迎。但至少在这种情况下,我可以使用只读字段来存储行为主题。
BehaviorSubject(或ReplaySubject)确实看起来像是为了这个目的,但是还有其他更好的方法吗?如果我应该使用这个主题,将主题作为注入参数,或者采用原始的可观察对象并在构造函数中本地构建主题会更有意义吗?
(顺便说一下,我知道如果源观察源还没有解决,需要处理第一个值。不要挂断它,这不是我要问的)
答案 0 :(得分:2)
我会使用ReactiveUI library的通用解决方案。 RUI有一种将IObservable<T>
映射到INotifyPropertyChanged
有状态属性的标准方法。
public class ObservableToINPCObject<T> : ReactiveObject, IDisposable
{
ObservableAsPropertyHelper<T> _ValueHelper;
public T Value {
get { return _ValueHelper.Value; }
}
public ObservableToINPCObject(IObservable<T> source, T initial = default(T))
{
_ValueHelper = source.ToProperty(this, p=>p.Value, initial);
}
public Dispose(){
_ValueHelper.Dispose();
}
}
ValueHelper
包含observable的current state
并在状态更改时自动触发正确的INPC通知。这是为你处理的锅炉板。
和扩展方法
public static class ObservableToINPCObject {
public static ObservableToINPCObject<T> ToINPC<T>
( this IObservable<T> source, T init = default(T) )
{
return new ObservableToINPCObject(source, init);
}
}
现在给出了
IObservable<int> observable;
你可以做到
var obj = observable.ToINPC(10);
并获取最新值
Console.WriteLine(obj.Value);
还假设Value是一个INPC支持属性,您可以在数据绑定中使用它。我一直使用ToProperty将我的observable作为WPF数据绑定的属性公开。
答案 1 :(得分:0)
要成为Rx-ish我建议避免使用第二个选项并使用第一个选项,但是可以通过以下两种方式之一进行修改。
要么(1)使你的班级成为一次性的,以便你可以干净地关闭对观察者的认购,或者(2)制定一种方法,让你清理个别的可观察物。
(1)
public class MyObject : IDisposable
{
private T CurrentT;
private IDisposable Subscription;
public MyObject(IObservable<T> externalSource)
{
Subscription = externalSource
.Subscribe((t) => { CurrentT = t; });
}
public void Dispose()
{
Subscription.Dispose();
}
public void DoSomething()
{
DoSomethingWith(CurrentT);
}
}
(2)
public class MyObject
{
private T CurrentT;
public IDisposable Observe(IObservable<T> externalSource)
{
return externalSource
.Subscribe((t) => { CurrentT = t; });
}
public void DoSomething()
{
DoSomethingWith(CurrentT);
}
}
两者都允许正确清理,两者都不使用主题。