如果我是你,我会尝试尽可能接近Rx的方式来实现你的类。
其中一个关键的基本原则是使用相对较少的具体类,这些类使用大量操作进行组合。所以你应该创建一些基本的构建模块并使用组合将它们结合在一起。
在Reflector.NET下我将首先看两个类:AnonymousObservable<T>
& AnonymousObserver<T>
。特别是AnonymousObservable<T>
被用作实例化observables的基础。实际上,如果您查看IObservable<T>
派生的对象,有几个专门的实现,但只有AnonymousObservable<T>
用于通用目的。
静态方法Observable.Create<T>()
实质上是AnonymousObservable<T>
的包装。
明显符合您的要求的其他Rx类是BehaviorSubject<T>
。受试者既是可观察者又是观察者,因为它记住了接收到的最后一个值,所以它符合你的情况。
鉴于这些基本的类,那么你几乎拥有创建特定对象所需的所有位。您的对象不应该从上面的代码继承,而是使用合成将您需要的行为集合在一起。现在
,我会建议一些改变你的类的设计,使他们其中Rx更兼容,从而更加composible和鲁棒性。
我会放弃你的Notifier<T>
班,转而使用BehaviourSubject<T>
。
我会放弃你的Observer<T>
班,转而使用AnonymousObserver<T>
。
然后,我会修改ObservableValue<T>
看起来像这样:
public class ObservableValue<T> : IObservable<T>, IDisposable
{
public ObservableValue(T initial) { ... }
public T Value { get; set; }
public IDisposable Subscribe(IObserver<T> observer);
public void Dispose();
}
的ObservableValue<T>
的实施将包裹BehaviourSubject<T>
而不是继承它暴露出IObserver<T>
成员将允许访问OnCompleted
& OnError
这不会使因为这个类代表一个价值而不是一个计算,所以这个意义太大了订阅将使用AnonymousObservable<T>
和Dispose
将清理包装的BehaviourSubject<T>
。
然后,我会修改ComputedValue<T>
看起来像这样:
public class ComputedValue<T> : IObservable<T>, IDisposable
{
public ComputedValue(IObservable<T> source) { ... }
public T Value { get; }
public IDisposable Subscribe(IObserver<T> observer);
public void Dispose();
}
的ComputedValue<T>
类将包装AnonymousObservable<T>
为所有用户和并用source
抢值的本地副本为Value
财产。 Dispose
方法将用于取消订阅source
观测值。
最后两个类是您的设计似乎需要的唯一真正的具体实现 - 这只是因为Value
属性。
接下来,你需要一个静态ObservableValues
类的扩展方法:
public static class ObservableValues
{
public static ObservableValue<T> Create<T>(T initial)
{ ... }
public static ComputedValue<V> Compute<T, U, V>(
this IObservable<T> left,
IObservable<U> right,
Func<T, U, V> computation)
{ ... }
}
的Compute
方法将使用AnonymousObservable<V>
执行计算并产生IObservable<V>
传递到由返回的ComputedValue<V>
构造方法。
带着所有这些地方,你现在可以这样写代码:
var ov1 = ObservableValues.Create(1);
var ov2 = ObservableValues.Create(2);
var ov3 = ObservableValues.Create(3);
var cv1 = ov1.Compute(ov2, (x, y) => x + y);
var cv2 = ov3.Compute(cv1, (x, y) => x * y);
//cv2.Value == 9
ov1.Value = 2;
ov2.Value = 3;
ov3.Value = 4;
//cv2.Value == 20
请让我知道这是有益的和/或如果有什么我可以详细阐述。
编辑:还需要一些一次性使用。
您还需要实现AnonymousDisposable
& CompositeDisposable
管理特别是在Compute
扩展方法订阅。看看使用Reflector.NET的Rx实现或使用下面的我的版本。
public sealed class AnonymousDisposable : IDisposable
{
private readonly Action _action;
private int _disposed;
public AnonymousDisposable(Action action)
{
_action = action;
}
public void Dispose()
{
if (Interlocked.Exchange(ref _disposed, 1) == 0)
{
_action();
}
}
}
public sealed class CompositeDisposable : IEnumerable<IDisposable>, IDisposable
{
private readonly List<IDisposable> _disposables;
private bool _disposed;
public CompositeDisposable()
: this(new IDisposable[] { })
{ }
public CompositeDisposable(IEnumerable<IDisposable> disposables)
{
if (disposables == null) { throw new ArgumentNullException("disposables"); }
this._disposables = new List<IDisposable>(disposables);
}
public CompositeDisposable(params IDisposable[] disposables)
{
if (disposables == null) { throw new ArgumentNullException("disposables"); }
this._disposables = new List<IDisposable>(disposables);
}
public void Add(IDisposable disposable)
{
if (disposable == null) { throw new ArgumentNullException("disposable"); }
lock (_disposables)
{
if (_disposed)
{
disposable.Dispose();
}
else
{
_disposables.Add(disposable);
}
}
}
public IDisposable Add(Action action)
{
if (action == null) { throw new ArgumentNullException("action"); }
var disposable = new AnonymousDisposable(action);
this.Add(disposable);
return disposable;
}
public IDisposable Add<TDelegate>(Action<TDelegate> add, Action<TDelegate> remove, TDelegate handler)
{
if (add == null) { throw new ArgumentNullException("add"); }
if (remove == null) { throw new ArgumentNullException("remove"); }
if (handler == null) { throw new ArgumentNullException("handler"); }
add(handler);
return this.Add(() => remove(handler));
}
public void Clear()
{
lock (_disposables)
{
var disposables = _disposables.ToArray();
_disposables.Clear();
Array.ForEach(disposables, d => d.Dispose());
}
}
public void Dispose()
{
lock (_disposables)
{
if (!_disposed)
{
this.Clear();
}
_disposed = true;
}
}
public IEnumerator<IDisposable> GetEnumerator()
{
lock (_disposables)
{
return _disposables.ToArray().AsEnumerable().GetEnumerator();
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
public bool IsDisposed
{
get
{
return _disposed;
}
}
}
如果你真的不关心LINQ,线程和其他类型的问题,那么为什么不使用ref变量,这可能是最简单的方法。 – Ankur