主旨:针对使用.net事件模式来达到异步操作的开发人员使用RX带来的优势
RX的优势
不论是从事传统的桌面应用程序编程还是基于网络的编程,你会时而不时的碰到异步操作。桌面应用程序开发肯定要考虑到/O操作和前台线程可能花费很长的时间导致其它线程阻碍。Silverlight禁止任何阻塞线程调度,所以你只能选用异步编程模型。然而现在的异步编程模型用户必须手动的管理异常和取消事件.为组合和过滤事件也要自己编码来实现,这将会很难去维护和编译。
另外,如果你的程序是多数据互相交互,传统的解决方法是通过把每个数据流作为一个单独的事件来进行管理的。例如:只要用户按下键盘,一个键盘事件将会推送到键盘事件的处理方法下。在这个键盘事件里面,你必须自己编码来过滤不同的数据流来获取当前事件所需要的数据。
目前,如果你想订阅事件,首先你要先创建事件句柄,之后你就可以订阅这个事件,示例如下:
/// Declare an event public event EventHandler<MouseEventArgs> MouseMove; /// Publish data MouseMove(this, args); ///Subscribe to an event MouseMove += (sender, args) => Display(args)
使用Rx,你可以处理多数据异步操作(数据可以来自于股票,计算机,网络等),并且订阅事件流通过Iobserver<T>接口,接口 IObservable<T> 维护一个依赖Iobserver<T>这个接口的列表,并且当它的状态发生改变会自动的通知它们。你可以通过标准化队列查询方式(LINQ)来操作observable这个队列。这时,你可以容易的通过标准的LinQ操作来实现多事件的过滤,组合,联合,执行功能。异常和取消也在RX的扩展中实现。
下面的示例展示了如何创建一个ISubject实例来代表事件流,Isubject继承于IObservable和IObserver这两个接口。和上一个示例使用相同的对象参数和订阅关系。
///Declare an observable public ISubject<MouseEventArgs> MouseMove; ///Publish data MouseMove.OnNext(args); ///Subscribe to an observable MouseMove.Subscribe(args => Display(args));
此外你可以使用计划表功能来实现何是开始这种订阅关系,或者何时把通知推送给订阅者。
过滤
传统事件模式的一个缺点就是一但事件被引发,事件处理程序都会立马被调用。而且事件都必须由事件源发引发然后被发送出来。为了让事件处理函数只处理自己关注的数据引发的事件,必须自己在事件自己编码来转换数据。
如以检测鼠标按下事件为例,在现在的事件模型中,你必须写事件处理程序 并且要用MouseEventArgs来作为参数,应用程序可以对引发事件的消息做出回应。在RX中,鼠标按下事件被作为一种带有点击信息的流进行处理。不论你何是点击鼠标,这些信息都在准备处理的流中。通过这种范式,事件或者事件流非常像List或其它集合,这也意味着我们可以把操作集合的方法用来操作事件。比如,你可以过滤掉鼠标在指定范围之外的点击,仅仅在范围内的点击才引发事件,或者你可以计算一段时间内点击 ,并把有效的点击 次数作为信息参数,类似的,你可以关注股票在一定时间的一定范围内的指数变化。这些通过RX非常容易实现。
通过这种方法,函数可以接收事件处理事件并把处理事件的流传递给应用程序。这将带给你在现在的编程模式中意想不到的灵活与方便。此外Rx还要充当管道功能来在后台过滤,异步,转换数据,你的事件处理函数只需处理收到的数据。这将会使你的代码是干净,易读和便于维护的。
组合
在现在的事件模式中,你几乎不能组合事件。不能订阅多下事件并且根据不同的事件结果来进行异步操作。在Rx中,一般的LINQ操作如SelectMany,Merge,等等已经实现的组件中,这样操作只需要合并多个事件流去返回给订阅者,如你可以创建一个观察者队列来监听鼠标按下和鼠标移动事件,之后你可以订阅这个台山观察队列,所以这就基本上实现了组合鼠标事件,其实也就是鼠标拖动事件。
操作事件
现在的事件模式中,事件针对与另一个服务交互(应用程序,函数,存储,进程)是隐藏数据源的,就像我们前面讨论的那样,RX是做为一个对象集合的。如,鼠标事件包含一个点值的集合,基于观察者对象的性质,它们可以做为函数参数,返回值,或者存在变量中。
解除事件订阅
现在有事件模式中,为了停止接收事件通知,你必须明确的解除订阅事件。RX可以简单的让你在特定的时间和特定的数据源。如,当你订阅一个观察队列展现的事件流时,你可以指定你订阅多长时间这个队列改变或者订阅一个时间间隔如订阅3-5分钟的事件流。或者其它事件发生时才会订阅事件。另外,当你订阅一个观察队列时,你可能得到一个IDisposable句柄通过这个句柄你可以通过调用Dispose来解除订阅。