c# - 在 IObservable<T> 接口(interface)中返回 IDisposable 的目的是什么?

标签 c# design-patterns system.reactive observer-pattern idisposable

我正在阅读 Head First Design Patterns 一书,并尽力将代码从他们的 Java 转换为 C#。在这本书讨论了观察者模式之后,它提到 Java 具有内置的类/接口(interface),.NET4 也是如此。所以我开始研究如何正确使用它,除了 Subscribe() 方法外,我已经弄明白了大部分内容。

如果您查看 MSDN Article当您尝试订阅 IObserver 时,该方法返回一个 IDisposable。为什么那是必要的?为什么不只实现一个基于方法参数取消订阅 IObserver 的方法呢? I researched the reason to use an IDisposable interface .我也读过这篇文章,但不太明白其中的区别/它想告诉我什么:

It returns a reference to an IDisposable interface. This enables observers to unsubscribe (that is, to stop receiving notifications) before the provider has finished sending them and called the subscriber's OnCompleted method.

最佳答案

取消订阅所需的信息因事件发布者管理订阅的方式而异。用于事件的方法——将委托(delegate)先前传递给 Add 方法的委托(delegate)传递给 Remove 方法——有点可行,但有一些明显的缺陷。其中:

  1. 通常需要事件发布者执行线性搜索来定位包含与订阅相关的信息的记录。如果一个事件有可能有很多订阅者,这可能会不必要地创建 O(N^2) 行为。如果订阅者保存在某种链表(链接对象或索引链接数组槽)中,并且取消订阅请求包含有关要取消的订阅的信息,则订阅和取消订阅都可以在恒定时间内处理。此外,取消订阅可以以无锁非阻塞方式安全且轻松地处理(在最有可能是无竞争数组槽的位置上使用一个 CompareExchange),这可以在 Finalize 上下文中安全地完成。
  2. 如果一个代表多次订阅处理顺序很重要的事件,并且代码试图取消第一个订阅,最后一个订阅将被取消,第一个订阅将保持有效。
  3. 如果订阅了委托(delegate)`D`,则订阅包含`A`、`B`、`C`和`D`的组播委托(delegate)`ABCD`,然后取消订阅`D`,那么委托(delegate) `DABC` 将按顺序保持订阅状态,即使代码试图取消订阅 `ABCD`。请注意,如果使用 `List` 而不是 `delegateType.Combine` 可以避免此问题,但其他问题仍然存在。

让事件订阅方法返回一个可用于取消订阅的对象可以避免这些问题。那么最大的问题就变成了应该使用什么类型的对象。我想到了三个选择:

  1. 委托(delegate)(可能无参数,返回 `void`)
  2. 一些 `ICancelSubscription` 接口(interface),使用单一方法(可能无参数,返回 `void`)取消订阅
  3. `IDisposable`,一个存在的接口(interface),有一个单一的无参数方法,广泛用于清理相关的目的

使用委托(delegate)是一个合理的选择。它可以很容易地封装取消订阅所需的任何信息,而用户不必担心该信息可能采用什么形式。使用委托(delegate)将需要分配至少一个额外的堆对象(对于委托(delegate)本身),可能还有两个(第二个是保存取消订阅信息的对象)。使用 IDisposable 本质上与使用委托(delegate)相同,不同之处在于委托(delegate)调用 Dispose 而不是 Invoke;但是,在许多情况下,IDisposable 在效率方面会稍有优势。使用其他一些接口(interface)也是可行的,但与使用现有的 IDisposable 相比并没有真正的优势。

关于c# - 在 IObservable<T> 接口(interface)中返回 IDisposable 的目的是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10625815/

相关文章:

c# - 使用 C# 将签名的 SOAP 消息创建为字符串

android - 使用 Dagger 2 发送数组列表

c++ - LLVM 是避免动态转换规则的异常(exception)吗?

c# - 为什么在没有 .NET 的 Reactive(Rx) 扩展的情况下不能使用 IObservable<T>?

c# - 如何使用 Reactive 限制消费顺序?

system.reactive - 如果其他 Observable 发出映射函数,则转换 Observable

c# - Gradle 支持构建 .Net 项目

c# - 如何在 Unity (C#) 中将字符串列表转换为单个字符串

java - 如何实现基于Key的CsvProcessing工厂设计模式

c# - TextReader.ReadToEnd 与 Stream.CopyTo