实验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. poj 1995 Raising Modulo Numbers 题解

    Raising Modulo Numbers Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 6347   Accepted: ...

  2. 数据库迁移利器:Migrator.Net

    几年前在做项目中第一次接触到了Migrator.Net,就深深被吸引住了,至此以后在新的大项目中,我都会使用Migrator.Net来创建或者更新数据库架构.曾经在项目中也发现了小bug并提交给了作者 ...

  3. 出现"未将对象引用设置到对象的实例“问题的总结

    今天做机房收费系统时,将DataGridView中的数据导入到Excel中,当运行到这一句代码”xlApp.Cells(rows + 2, j + 1) = DataGridView1(j, rows ...

  4. 【云计算】jenkins,docker,mesos,marathon,k8s相关资料

    参考资料: 基于Apache Mesos 构建高可靠,高可用的Jenkins CI:http://blog.csdn.net/ebay/article/details/43529401 Docker ...

  5. Virtualbox中Linux添加新磁盘并创建分区

    原文:https://www.linuxidc.com/Linux/2017-01/139616.htm ----------------------------------------------- ...

  6. SSIS无法在unicode和非unicode 字符串数据类型之间转换

    场景:SSIS从oracle抽到sqlserver,一个表对表到数据仓库ODS层的抽取,没有任何逻辑结果遇到问题: SSIS无法在unicode和非unicode 字符串数据类型之间转换 如下图2个字 ...

  7. discuz,ecshop的伪静态规则(apache+nginx)

    discuz(nginx): (备注:该规则也适用于二级目录) rewrite ^([^\.]*)/topic-(.+)\.html$ $/portal.php?mod=topic&topic ...

  8. 探寻不同版本号的SDK对iOS程序的影响

    PDF版本号:http://pan.baidu.com/s/1eQ8DVdo 结论: 同样的代码.使用不同版本号的SDK来编译.会影响MachO头中的值, 从而使程序表现出不同的外观. 代码: - ( ...

  9. java对象的强引用,软引用,弱引用和虚引用

    1.强引用 以前我们使用的大部分引用实际上都是强引用,这是使用最普遍的引用.如果一个对象具有强引用,那就类似于必不可少的生活用品,垃圾回收器绝不会回收它.当内存空 间不足,Java虚拟机宁愿抛出Out ...

  10. 开发移动 APP 时,你应注意这 5 个细节

    智能手机的普及带动了大批移动应用的诞生,这些应用能够帮助人们解决日常生活所面临的种种问题.Smart Insights 发表的一份报告指出,移动应用占人们使用智能手机总时间的89%,因此,为了确保你所 ...