在反应性扩展中,我们有
IObservable<T> Switch(this IObservable<IObservable<T>> This)
我想实现
IObserver<T> Switch(this IObservable<IObserver<T>> This)
会将传出事件切换到不同的观察者但是 以单一观察员身份呈现。
答案 0 :(得分:3)
此版本处理了几个问题:
存在可能导致事件丢失的竞争条件。如果观察者在一个线程上观察到一个事件而源observable在另一个线程上产生一个新的观察者,如果你不使用任何类型的同步,你可能最终在一个线程上的当前观察者上调用OnCompleted
另一个线程在同一个观察者上调用OnNext
。这将导致事件丢失。
与上述相关,默认情况下,观察者不是线程安全的。您永远不应该同时向观察者发出呼叫,否则您将违反主Rx合同。如果没有任何锁定,订阅者可以在OnCompleted
上调用currentObserver
,而另一个线程在同一个观察者上调用OnNext
。开箱即用,这种事情可以通过使用同步主题来解决。但由于我们还需要同步以解决上一个问题,我们可以使用一个简单的互斥锁。
我们需要一种方法来取消订阅源可观察对象。我假设当得到的观察者完成(或者错误)时,这是取消订阅源的好时机,因为我们的观察者被告知不会再发生任何事件。
以下是代码:
public static IObserver<T> Switch<T>(this IObservable<IObserver<T>> source)
{
var mutex = new object();
var current = Observer.Create<T>(x => {});
var subscription = source.Subscribe(o =>
{
lock (mutex)
{
current.OnCompleted();
current = o;
}
});
return Observer.Create<T>(
onNext: v =>
{
lock(mutex)
{
current.OnNext(v);
}
},
onCompleted: () =>
{
subscription.Dispose();
lock (mutex)
{
current.OnCompleted();
}
},
onError: e =>
{
subscription.Dispose();
lock (mutex)
{
current.OnError(e);
}
});
}
答案 1 :(得分:1)
public static IObserver<T> Switch<T>(this IObservable<IObserver<T>> This)
{
IObserver<T> currentObserver = Observer.Create<T>(x => { });
This.Subscribe(o => { currentObserver.OnCompleted(); currentObserver = o; });
return Observer.Create<T>
( onNext: v => currentObserver.OnNext(v)
, onCompleted: () => currentObserver.OnCompleted()
, onError: v => currentObserver.OnError(v));
}