如何确定一个方法应该返回 IEnumerable<T>
还是 IObservable<T>
?
为什么我会选择一种范式而不是另一种?
如何确定一个方法应该返回 IEnumerable<T>
还是 IObservable<T>
?
为什么我会选择一种范式而不是另一种?
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>)
T
被IObservable<T>
“推送”时,它被发送到队列中。IEnumerable<T>
“拉取”T
时,它会阻塞直到队列不为空,然后出队。IEnumerable<T>
转换为IObservable<T>
如果某个东西本来就是IEnumerable<T>
但您想将其处理为IObservable<T>
,则可以使用此方法:
IObservable<T> Observable.ToObservable(this IEnumerable<T>)
IEnumerable<T>
中“拉”出一个T
。T
时,它会通过IObservable<T>
“推”给你。IObservable<T>
。通过调用已经通过Subscribe()
注册了兴趣的Observers
上的OnNext()
来实现此操作。IEnumerable<T>
。通过调用GetEnumerator()
获取IEnumerator
,并调用MoveNext()
和Current
(foreach
就是这样编译的)。IObservable<T>
的良好候选者。这里信息是时间关键性的。作为数据的服务器,您需要尽快将其传递给客户端。客户端不知道何时准备好该数据。所以你要推送它给他们。IEnumerable
的良好候选者。这个数据很少更改,并且客户端(设置控件)更喜欢以他们自己的节奏消费它。IObservable<T>
是一个专门用于发布/订阅和其他模式的接口。在需要返回IObservable<T>
时,您会知道,如果没有特定的需求,则应返回IEnumerable<T>
。
评论中的问题更新
基本上,IObservable<>
使用“推”机制,而IEnumerable<>使用“拉”机制。如果你只需要获取数据列表而不需要通知订阅者进行更改(推),则可以使用IEnumerable
。如果订阅者(窗口,控件,其他客户端程序/例程等)需要了解数据何时更改,则使用IObservable<>
。一个例子是使用IObservable
从子线程更新Windows程序中的主UI线程(通常情况下,这是不可能的,除非进行繁琐的脚步操作。请阅读.NET反应扩展(Rx.NET)相关资料)。
使用 IEnumerable<T>
表示列表,使用 IObservable<T>
表示事件。非常简单。
IEnumerable
用于从集合中 拉取 数据,IObservable
则是用于订阅 推送 的数据。 - Nick