RX for .NET - 从Disposable.Create中调用observer.OnCompleted时没有任何反应

时间:2012-11-26 09:22:42

标签: c# system.reactive observable

我在C#中使用.NET的RX库。谁能解释为什么'observer.OnCompleted()'方法在以下代码中什么都不做:

var observableStream = Observable.Create<CustomMessage>(
       (observer) =>
           {
               CustomMessage cm = new CustomMessage();
               CustomMessage.Subscribe(observer.OnNext);

               return Disposable.Create(
               () =>
                   {
                       Console.WriteLine("Disposing...");
                       CustomMessage.Unsubscribe(observer.OnNext);                          
                       observer.OnCompleted();                //***Nothing happens here***
                   }
               );
       });

    //IObserver.OnException()
    public override void OnException(Exception e)
    {
        Console.WriteLine("Exception occurred - " + e.Message);
    }

    //IObserver.OnComplete()
    public override void OnUnsubscribe()
    {
        Console.WriteLine("Unsubscribed...");            
    }

    //IObserver.OnNext()
    public override void HandleNextMsg(IRVMessage msg)
    {
        Console.WriteLine("Instance received a message");
    }

IDisposable myDisposable = observableStream.Subscribe(HandleNextMsg, OnException, OnUnsubscribe);

//At some later point....
myDisposable.Dispose();

该代码旨在订阅CustomMessages流。它在设置订阅时使用我的CustomMessage类型注册observer.OnNext()方法。然后在处理订阅时取消注册observer.OnNext()。所有这一切都正常。每当收到CustomMessage时,都会调用我的'HandleNextMsg()'方法。

稍后当我希望终止我的订阅时,我会调用'Dispose()'并成功执行以下两行:

Console.WriteLine("Disposing...");
CustomMessage.Unsubscribe(observer.OnNext); 

然后我不再收到CustomMessages。但是,以下行虽然执行但没有做任何事情:

observer.OnCompleted(); 

我预计它会拨打电话:

Console.WriteLine("Unsubscribed...");

在某些时候,观察者和'OnUnsubscribe'方法之间的联系已经丢失,我想知道到底发生了什么。如何成功取消注册'observer.OnNext()',但'observer.OnCompleted()'什么都不做?

有人向我指出,仅仅因为我正在处理流并不意味着我应该调用'OnCompleted()',但我仍然想知道为什么它不起作用。

2 个答案:

答案 0 :(得分:3)

OnCompleted()用于通知订阅者上游序列(在您的情况下为CustomMessage)已结束。它并不意味着确认用户请求取消订阅已成功,这似乎是您尝试使用它的方式。 OnCompleted()是关于所有订阅者的序列的通知,而不是针对该序列的单个订阅的通知。

换句话说,您不应该在Dispose中调用它。毕竟,订阅者正在进行取消订阅,为什么需要通知?

至于为什么没有发生任何事情的实际技术原因,我猜测回调(按设计)在您已经处置时不会进行。只是一个理论,它并不是很相关。

答案 1 :(得分:2)

您看到的问题是由Observable.Create包装您传递的函数的方式以及您订阅生成的IObservable的任何观察者引起的。基本上,流程是:

  • Observable.Create返回AnonymousObservable。
  • AnonymousObservable将观察者包装在订阅中的AutoDetachObserver中。
  • AnonymousObservable从Subscribe返回AutoDetachObserver(实现IDisposable)。
  • AutoDetachObserver.Dispose设置其停止的标志,然后然后处理原始订阅函数返回的对象。此标志使观察者忽略对OnError和OnCompleted的未来调用,从而导致无法调用包装的观察者方法。

这个答案基于RX的v1.x,但我预计这在v2.0中没有变化。

如果您有一些代码需要运行,无论订阅如何结束(OnError,OnCompleted或Dispose),我建议Observable.Finally