两者之间有几个不同之处。
谁控制“枚举”
对于 observable(热或冷),是 observable 确定何时以及在哪个线程上返回值。另一方面,可枚举在您请求时获取每个值,并在请求枚举的线程上进行处理。
代码流
处理枚举通常在 for each 循环中完成(或偶尔获取枚举器并使用 while 循环)。您的代码通常会在继续之前处理所有值。 Observables 需要回调。阻止代码的进一步执行(比如阻止退出控制台应用程序)需要您额外的代码。 observables 有一些阻塞操作符,例如First,但它们是例外而不是正常使用的规则。
以这个简单的示例程序为例。使用可枚举,在继续下一部分之前写入所有值。但是,不能保证永远写入 observable 中的值。在程序终止之前写入了多少值几乎是一种竞争条件。
static void Main(string[] args)
{
var xs = Enumerable.Range(1, 10);
foreach (var x in xs)
{
Console.WriteLine(x);
}
//at this point, all values have been written
var ys = Observable.Range(1, 10);
ys.Subscribe(y => Console.WriteLine(y));
//at this point, no values have been written (in general)
//either add a Console.ReadKey or some sort of wait handle that
//is set in the OnCompleted of the observer to get values
}
异步进程
就像您必须编写额外的代码来阻塞和等待可观察对象一样,编写使用异步进程的 IEnumerable 也需要一些额外的工作。这就是两者之间的区别真正发挥作用的地方。
例如,在我当前正在处理的应用程序中,我需要搜索可能连接到串行端口的设备。 IObservable 非常适合这种情况,因为它允许我在找到每个设备时进行回调并通知应用程序,而无需阻塞以及操作完成时。这个 observable 符合 cold observable 的条件,因为除非有订阅者,否则它不会推送数据,并且每个订阅都会获得所有结果。 (与典型的冷可观察对象不同,我在订阅之前开始工作,但没有数据丢失,因为它被缓冲到重播主题中。)但是,由于异步,将其转换为 Enumerable 对我来说没有多大意义自然。