如何实现Switch for IObservable <iobserver <t>&gt;对于C#</iobserver <t>中的反应式扩展

时间:2013-04-15 06:04:52

标签: c# system.reactive

在反应性扩展中,我们有

IObservable<T> Switch(this IObservable<IObservable<T>> This)

我想实现

IObserver<T> Switch(this IObservable<IObserver<T>> This)

会将传出事件切换到不同的观察者但是 以单一观察员身份呈现。

2 个答案:

答案 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));
}