From events
正如我们早在书中所讨论的,.NET已经提供了一个事件驱动的编程模型。 虽然RX是一个更强大和有用的框架,但它是后来才开发出来的,并需要与现有的事件模型集成。RX提供了接受事件并将其转换为可观测物序列的方法。有几种不同的种类可供选择。以下是几种常见事件模式的选项:
这些重载令人混乱,但关键是找出它们的事件签名加以区别。如果签名是EventHandler可以用第一个例子,如果委托是EventHandler的子类,你可以使用第2个例子,如果委托是泛型的,那么使用第3个例子。
From Task
ToObservable()方法的重载提供了转换为可观测物范式的简便方式。AsyncSubject<T>与Task<T>类似,它们都从异步源返回单个值,并为value缓存任何repeated请求或late请求结果。
第一个ToObservable()扩展方法重载可以将其看作是对Task<T>的扩展,它的运作方式很简单:
- 如果Task已经在一个RanToCompletion状态,将值添加到队列并完成队列
如果Task被取消,队列将出错并抛出一个TaskCanceledException。
- 如果Task失败,队列将出错并抛出一个任务的内部异常
- 如果Task尚未完成,继续添加到Task以适当履行上述行动
使用时有两点需要注意:
- .Net4.5几乎所有的I/O密集型函数都返回Task<T>
- 如果Task<T>合适,就应该使用它替代IObservable<T>,因为它在类型系统中交换单值结果。换句话说,一个返回single value的函数应该返回一个Task<T>,而不是IObservable <T>。如果你需要combine其他可观测物,再使用ToObservable()方法。
使用扩展方法也很简单,例如下面的例子:
Output:
Test
completed
还有另外一种重装载,将Task(非泛型)转换为IObservable<Unit>。
From IEnumerable<T>
最后一个ToObservable重载接受一个IEnumerable<T>。它像是Observable.Create的辅助方法,内部带有一个foreach循环。
上面的这种粗暴的实施是幼稚的。它没有正确的disposal,也不处理异常,没有一个好的并发模型。
从IEnumerable<T>转换到IObservable<T>时,你应该仔细考虑什么是你真正想实现的。你应该仔细衡量并测试执行你的决策的影响,要考虑到阻塞同步(pull)性质的IEnumerable<T>有时与异步(push)性质的IObservable<T>配合得并不是很好。
可以使用IEnumerable,IEnumerable<T>、数组或集合作为Observable队列的数据类型(既:将IEnumerable,IEnumerable<T>、数组或集合作为数据发送)。
From APM
From APM就是from the Asynchronous Programming Model(异步编程模型)。接下来我们要看的重载可以将APM转换为可观测物序列。在.Net编程中有这样一种风格,可以以方法名Begin开始的方法,和方法名以End开始的方法,还有标志性的IAsyncResult参数类型,在I/O API中很常见,例如下面:
APM,或异步模式,使一个非常强大但笨拙的方式为.NET程序执行长时间运行的I/O绑定工作。如果我们使用同步访问IO,如WebRequest.GetResponse()或者Stream.Read(...),在等待I/O完成时,我们会阻塞一条线程但不进行任何工作。在繁忙的服务器上执行大量并发工作,但在等待I/O完成时却保持空闲状态有可能是相当浪费的。
APM可以实现在硬件设备驱动层工作,同时不需要阻塞任何线程。我们可以使用Observable.FromAsyncPattern方法来使用用异步编程模型,同时避免其笨拙的API。Observable.FromAsyncPattern有30种重载,这里仅介绍一些,你也可以挑选自己所需要的来使用。
首先我们看看APM的正常模式。我们将看到BeginXXX方法接受零或多个数据参数,随后是AsyncCallback和Object;同时BeginXXX方法也会返回一个IAsyncResult类型的token。
EndXXX方法将接受一个IAsyncResult,也就是BeginXXX方法的返回值;同时EndXXX自身也可以返回一个值。
假如FromAsyncPattern方法的泛型参数与传入BeginXXX方法的数据参数如果有对应关系,那么EndXXX方法的返回类型就也会有对应关系。
我们先来看一下BeginXXX方法的部分。在下面的例子中,我们可以看到BeginRead方法的参数中有一个byte[]和两个int与FromAsyncPattern方法的泛型参数相对应:
Observable.FromAsyncPattern的返回类型并不是可观测物队列,而是返回类型为可观测物队列的委托。委托的签名将会与FromAsyncPattern方法的泛型参数相匹配,除了代表EndXXX方法的返回类型的那个参数类型被包裹在可观测物队列中。
至此,我们看到了BeginXXX方法的数据参数和EndXXX方法的返回类型与FromAsyncPattern方法的泛型参数相互对应。
现在,我们已经介绍了查询操作的第一步:创建可观测物队列。让我们快速的回顾一下:
- Factory Methods
- Observable.Return
- Observable.Empty
- Observable.Never
- Observable.Throw
- Observable.Create
- Unfold methods
- Observable.Range
- Observable.Interval
- Observable.Timer
- Observable.Generate
- Paradigm Transition
- Observable.Start
- Observable.FromEventPattern
- Task.ToObservable
- Task<T>.ToObservable
- IEnumerable<T>.ToObservable
- Observable.FromAsyncPattern
创建可观测物队列是我们实际应用RX的第一步:创建队列,然后将其暴露给订阅者。现在,我们学习了如何创建一个观测物队列,接下来我们将要学习可以查询可观测物队列的操作。
8篇了,不错不错!
你头像也不错!
@Oncle:谢谢支持,我会尽量全部翻译完的~头像是自画像,哈哈~