【问题标题】:When to use IEnumerable vs IObservable?何时使用 IEnumerable 与 IObservable?
【发布时间】:2013-06-13 08:11:45
【问题描述】:

如何确定一个方法应该返回IEnumerable<T> 还是IObservable<T>

为什么我会选择一种范式而不是另一种?

【问题讨论】:

  • 这就像在问如何决定一个方法应该返回一个 List 还是一个 DateTime... 这些类型在语义上并不相关。
  • 我同意@MatthewWatson,两个界面的用途不同。
  • IEnumerable 用于 pulling 集合中的数据,IObservable 用于订阅 pushed 数据。
  • 他们不是都在枚举。 IEnumerable 基本上就像“给我下一项”,IObservable 是“嘿看,有下一项”。
  • 我认为 IObservable 和 IEnumerableIObservable 在语义上是非常相关的。他们可能在很多方面是对立的,但这并不意味着他们是无关的。事实上,Eric Meijer 已经就这一点进行了多次讨论,可以在这里找到一个视频:channel9.msdn.com/Shows/Going+Deep/… - 这也不是一个愚蠢的问题。在许多情况下,选择一种或另一种会对系统设计产生深远的影响。

标签: c# .net ienumerable system.reactive


【解决方案1】:

类型

  • IEnumerable<T>
    • 你反复从T的序列中“拉”
  • IObservable<T>
    • T 的序列正在向您“推送”

为什么我会选择一种范式而不是另一种?

您通常“选择”一种范式而不是另一种范式。通常,一个会自然而然地成为正确的选择,而另一个则没有任何意义。

示例

考虑以下示例:

  • 一个巨大的 CSV 文本文件的每一行都有一个项目,您想一次处理一个项目,而不是一次将整个文件加载到内存中:IEnumerable<List<string>>

  • 您正在运行 HTTP Web 服务器:IObservable<WebRequest>

  • 您希望以广度优先的方式获取树数据结构的节点:IEnumerable<Node>

  • 您正在响应用户界面按钮点击:IObservable<Click>

在每个示例中(尤其是 IObservable<T> 案例),使用其他类型是没有意义的。

但如果我想使用“其他”类型怎么办...

IObservable<T>IEnumerable<T>

如果某事物自然是IObservable<T>,但您想将其视为IEnumerable<T>,则可以使用以下方法:

IEnumerable<T> Observable.ToEnumerable(this IObservable<T>)
  • TIObservable&lt;T&gt;“推送”时,它会被发送到队列中。
  • 当您尝试将 TIEnumerable&lt;T&gt; 中“拉出”时,它会阻塞直到队列不为空,然后出队。

IEnumerable&lt;T&gt;IObservable&lt;T&gt;

如果某事物自然是IEnumerable&lt;T&gt;,但您想将其视为IObservable&lt;T&gt;,则可以使用以下方法:

IObservable<T> Observable.ToObservable(this IEnumerable<T>)
  • .NET 线程池中的线程将反复尝试从 IEnumerable&lt;T&gt; 中“拉”T
  • 每次它“拉”T,它都会通过IObservable&lt;T&gt;“推”你。

【讨论】:

    【解决方案2】:

    如果你想推送数据给你的方法的调用者在你方便的时候,使用IObservable&lt;T&gt;。您可以通过在Observers 上调用OnNext() 来执行此操作,该兴趣通过Subscribe() 注册。

    如果您希望方法的调用者数据方便时,请使用IEnumerable&lt;T&gt;。他们通过调用GetEnumerator() 来获取IEnumerator 并调用MoveNext()Currentforeach 编译为此)来做到这一点。

    更新:也许最好举一些例子:

    返回银行货币价格的函数非常适合IObservable&lt;T&gt;。这里的信息是时间关键的。作为此数据的服务器,您需要尽快将其发送到客户端。客户端不知道该数据何时准备就绪。所以你把它推给他们。

    返回特定金融工具的有效交易日并用于填充日历控件上的停电日的函数是 IEnumerable 的良好候选者。此数据很少更改,并且客户端(设置控件)更喜欢以它指定的速度使用它。

    【讨论】:

    • 这是正确的,但我为什么要选择一种范式而不是另一种呢?
    【解决方案3】:

    IObservable&lt;T&gt; 是一个专用接口,可用于发布/订阅和各种其他模式。您会知道何时需要返回 IObservable&lt;T&gt;,因此如果没有特定需要,请返回 IEnumerable&lt;T&gt;

    更新评论中的问题

    基本上,IObservable&lt;&gt; 使用“推送”机制,而 IEnumerable 使用“拉取”机制。如果您只想获取不需要通知订阅者更改(推送)的数据列表,那么您可以使用IEnumerable。如果订阅者(窗口、控件、其他客户端程序/例程等)需要知道数据何时更改,则使用IObservable&lt;&gt;。一个例子是使用 IObservable 从子线程更新 windows 程序中的主 UI 线程(通常,如果没有花哨的步法,这将无法完成。阅读 .NET Reactive Extensions (Rx.NET)。

    【讨论】:

    • 为什么不总是返回 IObservable 而不是 IEnumerable? Surley IObservable 是功能的超集?
    • 不正确。您正在描述 Observable (类)。 IObservable 只是一个提供更改通知的接口 - 不一定与集合有关。
    • 在上面添加了对您问题的答案....感谢您接听 Simon - 我累了,打算写课。
    【解决方案4】:

    使用IEnumerable&lt;T&gt; 表示列表,使用IObservable&lt;T&gt; 表示事件。轻松愉快。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-04-02
      • 1970-01-01
      • 2013-06-02
      • 1970-01-01
      • 1970-01-01
      • 2013-06-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多