subject.Dispose() 对比 subject.OnCompleted()

subject.Dispose() vs subject.OnCompleted()

Subject 上调用 .Dispose().OnCompleted() 有什么区别?

通常我会安排订阅以停止监听可观察对象并在代码中的任何地方不再有用时完成一个主题,

Usually i dispose subscription to stop listening an observable and complete a subject when it's no longer usefull[sic] anywhere on the code

我认为你把那些倒退了。我不熟悉 rx.net,但我知道 IDisposable 和 Observable 模式。 IDisposable 用于在您完全使用完某个对象并且不再有用时从该对象释放资源。 OnCompleted 用于当您完成观察(提供者已完成发送通知)时,即使该对象可能仍有其他用途。

根据Subject<T>.Dispose方法的documentation

Releases all resources used by the current instance of the Subject<T> class and unsubscribe all observers.

似乎在处理 Subject 之后尝试对它做任何事情都会导致 ObjectDisposedException。例如,您不能 Subscribe 到已处置的 Subject。在处理 Subject 时处于活动状态的任何订阅也将被处理,并且未订阅的观察者将 不会 收到 OnCompleted 通知。

相反,通过调用其 OnCompleted 方法完成的主题仍然可以随时订阅,在这种情况下订阅的观察者将立即收到 OnCompleted 通知。当然,如果完成的主题是像ReplaySubject这样的缓冲类型之一,那么观察者将在最终OnCompleted.

之前收到许多OnNext通知。

我个人会考虑调用Dispose到一个即将被丢弃的ReplaySubject,以加速其内部缓冲区使用的RAM的回收。我不确定这是否会有所不同,因为 Dispose 通常应该释放非托管资源,并且缓冲区使用的内存很可能是托管的。

在主题上调用 .Dispose().OnCompleted() 之间存在非常重要的语义差异。

考虑这段代码:

Subject<int> subject = new Subject<int>();

IObservable<int[]> query = subject.ToArray();

IDisposable subscription =
    query
        .Subscribe(xs => Console.WriteLine(String.Concat(xs)));

subject.OnNext(1);
subject.OnNext(2);

如果我随后调用 subject.OnCompleted(),我会将 12 写入控制台。但是,如果我调用 subject.Dispose(),则不会打印任何内容。

一些运算符,例如我的示例代码中的 .ToArray(),期望 .OnCompleted() 调用产生任何值。

了解您在 subject 上执行的查询以了解如何正确结束它很重要 - 在某些情况下两种方式都有效。

不过,我觉得您处理订阅和完成科目的做法是正确的。