实验3-引入 .net 中的 events 到 Rx

目标:前面实验中的使用各种工厂构造方法创建一个 可观察序列是一个部分。把 .net 中现有的异步数据源进行关联

是更重要的事情。在这次实验中我们将看到使用 FromEvent 操作来把 .net 中的 event 作为一个 observable 序

列导入到 Rx 。每次事件触发,一个 OnNext 消息会被传递到 observable 序列。

背景:Rx 的目标不是代替现有的异步编程模型,比如 .net 事件,异步模型或者 Task Parallel Library。这些已有

的理论通常很适合直接使用,比如在 C# 中使用 event handles。然而,使用这些低级的理论可能使程序员必须疲

惫地进行资源维护(比如事件的注销 -=)和进行重新改造(比如你知道怎样过滤一个事件吗?)。这样会使程序员

从实际问题的解决上分心。在下面的实验中,我们会展示 Rx 的强大源于何处:异步数据源的组合。

1、Windows Form 是 framework api 中包含很多事件的很好的示例。为了减少干扰,下面不会直接创建一个

Windows Form 工程而是使用一个控制台程序创建。同时需要添加 System.Windows.Forms 和

System.Drawing,也需要引入 System.Reactive 和 System.CoreEx:

2、输入下面的代码来创建一个新 form,并且通过 Application.Run 运行:

3、接下来我们会使用鼠标的 MouseMove 事件:

虽然能很好的工作,但是传统的 .net 事件有很多的限制:

1)事件隐藏了数据源。必须通过事件中的代码看到它。你以前有没有把 MouseMove 事件作为一个 Point

值的一个集合?在 Rx 的世界里,我们把 events 仅仅看作一个固有形式的 observable 序列:你的鼠标是

一个 Point 值的数据库。

2)事件不能传递出去,比如 一个产生 Point 值的事件不能传递出数据作为 GPS 的服务。深层的原因是因为

事件不是 first-class objects。在 Rx 的世界里,每一个 observable 序列可以用一个可以被传递和保持的

对象代表。

3)事件不能被容易的组合。例如,你不能雇佣一个数学家去按照一定的规则写一个可以过滤事件产生的数据

的过滤器。在 Rx 的世界里,由于 observables 的 first-class 的本质,我们可以提供如 Where 这种基本操作

4)Events 需要你手动维护,需要你记得传递给它的委托。在 Rx 的世界里,你可以得到一个 IDisposable 句柄

来 unsubscribe。

4、下面让我们看一下 Rx 的使用。我们使用 FromEvent 方法来向 Rx 导入一个事件,然后可以获得关联事件所获

得的 EventArgs对象。

我们深入的讲解一下:

1)这个 FromEventPattern 方法把指定事件转换成一个传递 IEvent 类型元素(既包含 sender 也

包含 event 参数 )的 observable 序列。把鼠标悬停在 var 关键字上,显示变量 moves 的类型:

2)当调用 Subscribe 时,一个 handler 附加到底层的事件。每次事件触发的时候,它的 sender 和

arguments 被装到一个 IEvent<MouseEventArgs> 对象中,然后被发送到它的所有的观察者

3)在 OnNext handler 里面,因为强类型,我们可以“点” 出事件的 Location 属性。

4)可以使用 FromEvent 操作返回的 IDisposable 对象进行事件句柄的清除。在 using 代码块里会自动

调用 Dispose 方法,自动清除事件句柄。

5、为了讲述更深入一些,我们看一下另一个 Windows Form 事件。首先添加一个 TextBox 控件

到这个 form 对象中:

6、重构代码,来拥有 Form 对象的 MouseMove 和 TextBox 的 TextChanged 事件。这次,我们输出

到控制台作为 log。在实验5 中我们会学到一个叫做 Do 的方法来做这件事。

从上面的代码中我们并没有获得更多。传统的 .net 事件并没有明确的展示 数据导向的本质。这个特别

的事件是一个很好的 observation 的示例:从 TextChanged 事件句柄中,当文字改变时你并没有立即

获得文字,这也是 99% 的 event 的这样做的。

最后,我们注意到 IDisposable 注册句柄的联合类型 System.Disposables 命名空间下的

CompositeDisposable 类。当它调用 dispose 方法时会释放掉 所有它包含的 IDisposable 对象。

7、下面是一段示例的输出:

结论:.NET 中的事件仅仅是一种形式的 异步数据源。为了作为 observable collections 来使用它们,Rx

提供了 FromEvent 方法。返回一个包含 Sender 和 event arguments 的 IEvent 类型的对象。

练习4 - 第一次浏览一些标准的 Query Operators

目标:把 observable 序列作为异步数据源,从而使它们可以像很多其它的数据源一样被查询。

一谈到 C# 编程中的查询,会立即想到 LINQ。在这个实验中,将演示如何使用 LINQ 语句对 observable

序列进行查询。

1、接着上面实验的代码,我们看一下刚才写的使用 FromEvent 操作引入到 Rx 的处理 UI 事件的代码:

回忆一下 moves 和 input 集合的类型都是 IObservable<IEvent<TEventArgs>> 类型的对象,TEventArgs

是从 FromEvent 中获得的参数类型。一般我们不会对捕获的 IEvent 里的参数都感兴趣,我们可以去掉多余的东西。

2、在传统的 .net event 世界里,很多人都会这样写代码:

在第一个示例中使用 if 语句进行过滤;在第二个示例中使用另一个本地变量

3、在 Rx 的这个新世界里,我们可以做得更好。因为 observable 序列可以用 IObservable<T>对象代表

它们所有我们可以为 operators 提供一整套的(扩展)方法。我们使用 LINQ 查询方法重写一下上面的事件

处理代码:

使用 C# 中的查询语句,我们去掉了 IEvent<MouseArgs> 和 IEvent<EventArgs> 数据类型,得到

更喜欢的 Point 和 string。从而我们得到我们想要的 moves 和 input 的更有意义的数据类型的 observable 序列

上面的查询语句可以简化为 query 扩展方法:

背景:把异步数据源定义为 first-class 对象的能力决定了 operators 的定义。

4、为了减少 input 序列中的噪音,我们可以轻松的过滤到鼠标移动的二分线(x 和 y坐标相等的点)。我们可以

使用 LINQ 中的  Where 关键字:

变量 moves 和 overFirstBisector 的类型都是 IObservable<Point>.

5、示例的输出如下,每个传递的鼠标 move 通知 都符合我们指定的过滤查询约束。

结论:我们可以使用连续的操作来过滤出符合我们要求的序列。LINQ 语句提供了一个简单的方式来执行

通常的操作。后面我们会继续讨论。

练习 5 - 更多的查询操作来 驯化 input

目标:observable 序列在正常使用中的行为不是很好。通常我们想获得一种形式的数据,却得到另一种数据形态。

上面的实验已经可以看出一些了。但是通常会有更多形式的病态数据源。例如,会输出重复的值。如果对于用户来说

一个源运行的太快而不好处理时?我们会在下面处理这种情形。

下面演示异步“建议列表”。一个用户在文本框中输入一个词汇,则向用户提供一个以这个词汇为开始的从 web

service 获取的“建议列表”。。为了防止 UI 卡死,我们使用异步的方式。Rx 非常适合处理这种问题。首先

看一下 TextBox 控件的行为。

1、在下面我们不再需要 MouseMove 事件:

2、

稍后继续整理翻译

微软 MSDN Rx 网址:The Reactive Extensions (Rx)

本文翻译原英文文档下载:Hands-on Lab Reactive Extensions for .NET

2、Reactive Extensions for .NET(译)的更多相关文章

  1. Reactive Extensions入门

    https://www.cnblogs.com/yangecnu/archive/2012/11/03/Introducting_ReactiveExtensions.html 前面我写过7篇文章粗略 ...

  2. Reactive Extensions(Rx) 学习

    Bruce Eckel(著有多部编程书籍)和Jonas Boner(Akka的缔造者和Typesafe的CTO)发表了“反应性宣言”,在其中尝试着定义什么是反应性应用. 这样的应用应该能够: 对事件做 ...

  3. Reactive Extensions介绍

    Reactive Extensions(Rx)是对LINQ的一种扩展,他的目标是对异步的集合进行操作,也就是说,集合中的元素是异步填充的,比如说从Web或者云端获取数据然后对集合进行填充.Rx起源于M ...

  4. 牛刀小试:使用Reactive Extensions(Rx),对短时间内多次发生的事件限流

    我之前有一篇文章介绍到了Reactive Extension这个组件,请参考下面的文章,其中有一些基本的概念和相关的链接 牛刀小试:使用Reactive Extensions(Rx),一行代码实现多线 ...

  5. Reactive Extensions(Rx)并发浅析

    Reactive Extensions(Rx)并发浅析 iSun Design & Code .Net并行编程 - Reactive Extensions(Rx)并发浅析 关于Reactive ...

  6. 使用Reactive Extensions(Rx),对短时间内多次发生的事件限流

    使用Reactive Extensions(Rx),对短时间内多次发生的事件限流 牛刀小试:使用Reactive Extensions(Rx),对短时间内多次发生的事件限流 我之前有一篇文章介绍到了R ...

  7. Reactive Extensions 相见恨晚的Rx.Net

    何为Reactive Extensions(Rx) Rx是一个遵循函数式编程的类库,它引用观察者以及迭代器设计模式对可观察对象产生的数据进行异步消费.使用Rx, 开发人员将使用LINQ运算符操作异步数 ...

  8. .Net并行编程 - Reactive Extensions(Rx)并发浅析

    关于Reactive Extensions(Rx) 关于Reactive Extensions(Rx),先来看一下来自微软的官方描述: The Reactive Extensions (Rx) is ...

  9. Rx (Reactive Extensions)

    The Reactive Extensions (Rx) is a library for composing asynchronous and event-based programs using ...

随机推荐

  1. 数学图形(2.13)Spherical trochoid曲线

    该曲线与上一节的herical cycloid球面外摆曲线 很相似,难道这是球面内摆曲线? #http://www.mathcurve.com/courbes3d/cycloidspheric/tro ...

  2. STM32F103 GU906B模块GPRS、短信收发、拨号等功能的实现

    这个程序搞了我很久,尤其是对如何提高响应速度上,程序流程很简单,大概就是: 发送AT指令->等待模块响应->一旦响应了,立即返回,并处理掉. 这个程序不一定只能用在GU906上,程序框架在 ...

  3. hello-循环神经网络(RNN)原理

    主要的应用:机器翻译,自然语言处理,文本处理,语音识别, 图像描述生成 (Generating Image Descriptions), 图像问答QA.... 循环神经网络(RNN)原理通俗解释 1. ...

  4. DataBindings的用法

    在C#操作数据库过程中,针对一般的文本控件,比如TextBox,Label等,我们赋值直接使用类似TextBox.Text=****的方式来进行,这种方式从某种意义上来说的确是最简便的方式,但是对于复 ...

  5. Servlet学习笔记(一):生命周期

    一.Servlet 生命周期: Servlet 生命周期可被定义为从创建直到毁灭的整个过程.以下是 Servlet 遵循的过程:初始化——响应请求——终止——回收 Servlet 通过调用 init ...

  6. php 上传视频的代码,

    <html> <head> <meta http-equiv="Content-Type" content="text/html; char ...

  7. binlog的几种复制形式

    binlog的几种复制形式 MySQL 5.5 中对于二进制日志 (binlog) 有 3 种不同的格式可选:Mixed,Statement,Row,默认格式是 Statement.总结一下这三种格式 ...

  8. python 网络请求类库 requests 使用

    python 网络请求类库 requests 使用 requests是 为python封装的强大 REST 操作类库 githubhttps://github.com/kennethreitz/req ...

  9. Python List+Tuple+Dict+Set小结

    创建List:L = ['Adam', 'Lisa', 'Bart', 'Gechong', 'Kongming'] 显示List:L[0] 遍历List:print (L)和for循环 更新List ...

  10. centos7 yum安装遇到报错:Head V3 RSA/SHA256 Signature, key ID 352c64e5: NOKEYer

    centos7 yum安装时遇到错误:Header V3 RSA/SHA256 Signature, key ID 352c64e5: NOKEY 无法安装时,可按如下方法解决: This mini ...