何时使用IEnumerable vs IObservable?

时间:2013-06-13 08:11:46

标签: c# .net ienumerable system.reactive

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

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

4 个答案:

答案 0 :(得分:24)

类型

  • IEnumerable<T>
    • 你从T的序列中反复“拉”
  • IObservable<T>
    • T的序列被“推”给你
  

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

你通常“选择”一种范式而不是另一种范式。通常一个人自然而然地作为正确的选择脱颖而出,另一个没有任何意义。

实施例

请考虑以下示例:

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

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

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

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

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

但是,如果我想使用“其他”类型...

IObservable<T>IEnumerable<T>

如果某些内容自然是IObservable<T>,但您希望将其处理为IEnumerable<T>,则可以使用此方法执行此操作:

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

IEnumerable<T>IObservable<T>

如果某些内容自然是IEnumerable<T>,但您希望将其处理为IObservable<T>,则可以使用此方法执行此操作:

IObservable<T> Observable.ToObservable(this IEnumerable<T>)
  • 来自.NET线程池的线程将反复尝试从T“拉出”IEnumerable<T>
  • 每当它“拉”一个T时,它就会通过IObservable<T>“推送”给您。

答案 1 :(得分:5)

如果您希望数据推送到方便方法的调用者,请使用IObservable<T>。您可以通过OnNext()Observers上注册感兴趣的Subscribe()来执行此操作。

如果您希望方法的调用者在方便时数据,请使用IEnumerable<T>。他们通过致电GetEnumerator()获取IEnumerator并致电MoveNext()Currentforeach汇编到此处)来实现此目的。

更新:也许最好给出一些例子:

在银行中返回货币价格的功能是IObservable<T>的合适人选。这里的信息对时间至关重要。作为此数据的服务器,您需要尽快将其发送到客户端。客户端不知道该数据何时准备就绪。所以你把它推给他们。

返回特定金融工具的有效交易日并用于填充日历控件上的停电天数的函数是IEnumerable的良好候选。这些数据很少改变,客户端(设置控件)更愿意按照它指示的速度消耗它。

答案 2 :(得分:4)

IObservable<T>是一个专门的接口,可用于pub / sub和各种其他模式。您会知道何时需要返回IObservable<T>,因此如果没有特定需要,请返回IEnumerable<T>

在评论中更新问题

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

答案 3 :(得分:1)

使用IEnumerable<T>来表示列表,使用IObservable<T>来表示事件。容易腻。