第 11 章 反应式扩展 反应式扩展
本作品已使用人工智能进行翻译。欢迎您提供反馈和意见:translation-feedback@oreilly.com
Reactive Extensions for .NET(简称 Rx)是专为处理异步和基于事件的信息源而设计的。Rx 提供的服务可以帮助您协调和同步代码对来自此类信息源的数据做出反应的方式。我们在第 9 章中已经了解了如何定义和订阅事件,但 Rx 提供的远不止这些基本功能。它为事件源提供了一种抽象,这种抽象的学习曲线比事件更陡峭,但它提供了一组强大的操作符,使得组合和管理多个事件流比使用委托和 .NET 事件所提供的自由组合要容易得多。
Rx 的基本抽象IObservable<T> 表示项目序列,其操作符被定义为该接口的扩展方法。这听起来可能很像 LINQ to Objects,而且也有相似之处--不仅IObservable<T> 与IEnumerable<T> 有很多共同之处,而且 Rx 还支持几乎所有标准的 LINQ 操作符。如果您熟悉 LINQ to Objects,那么您也会对 Rx 感到得心应手。不同的是,在 Rx 中,序列不那么被动。与IEnumerable<T> 不同的是,Rx 源不会等待别人询问它们的项目,Rx 源的消费者也不能要求得到下一个项目。相反,Rx 采用的是推送模式,源会在有项目时通知接收者。
例如,如果您正在编写一个处理实时金融信息(如股票市场价格数据)的应用程序,IObservable<T> 是一个比IEnumerable<T> 更自然的模型。由于 Rx 实现了标准的 LINQ 操作符,因此您可以编写针对实时源的查询--您可以使用where 子句缩小事件流的范围,或按股票代码对它们进行分组。Rx 在标准 LINQ 的基础上,增加了自己的操作符,将实时事件源的时间性质考虑在内。例如,您可以编写一个查询,只为价格变动频率超过某个最低比率的股票提供数据。
Rx 面向推送的方法使其比IEnumerable<T> 更适合类事件源。但为什么不直接使用事件,甚至是普通的委托呢?Rx 解决了这些替代方案的四个缺陷。首先,它定义了源报告错误的标准方式。其次,它能以定义明确的顺序交付项目,即使在涉及众多源的多线程场景中也是如此。第三,Rx 提供了一种明确的方式,在没有更多项目时发出信号。第四,由于传统的事件是由一种特殊的成员(而不是普通对象)来表示的,因此对事件的处理有很大的限制--例如,不能将事件作为参数传递给方法。Rx 使事件源成为一等实体,因为它只是一个对象。这意味着您可以将事件源作为参数传递,将其存储在字段中,或在属性中提供--所有这些都是普通 .NET 事件无法做到的。当然,您可以将委托作为参数传递,但这并不是一回事--委托可以处理事件,但并不代表事件。由于无法传递实际事件本身,因此无法编写订阅某个 .NET 事件的方法。Rx 将事件源表示为对象,而不是类型系统的特殊功能,从而解决了这个问题。
当然,这些都是在IEnumerable<T> 世界中免费获得的功能。IEnumerable<T> 使消费者一次一个地检索项目,因此排序是明确的,但对于普通的事件和委托,没有任何东西可以强制执行这一点。IEnumerable<T> 会告诉消费者集合何时结束,但如果使用简单的回调,最后一次调用是什么时候就不一定清楚了。IObservable<T> 会处理所有这些可能发生的情况,将我们在IEnumerable<T> 中认为理所当然的事情带入事件的世界。
通过提供一个连贯的抽象来解决这些问题,Rx ...
Become an O’Reilly member and get unlimited access to this title plus top books and audiobooks from O’Reilly and nearly 200 top publishers, thousands of courses curated by job role, 150+ live events each month,
and much more.
Read now
Unlock full access