《C#并发编程经典实例》—— 转换.NET事件

简介: 问题 把一个事件作为 Rx 输入流,每次事件发生时通过 OnNext 生成数据。 解决方案 Observable 类 定 义 了 一 些 事 件 转 换 器。 大 部 分 .NET 框 架 事 件 与 FromEventPattern 兼 容, 对于不遵循通用模式的事件,需要改用 FromEvent。

问题

把一个事件作为 Rx 输入流,每次事件发生时通过 OnNext 生成数据。

解决方案
Observable 类 定 义 了 一 些 事 件 转 换 器。 大 部 分 .NET 框 架 事 件 与 FromEventPattern 兼 容, 对于不遵循通用模式的事件,需要改用 FromEvent。

FromEventPattern 最适合使用委托类型为 EventHandler 的事件。很多较新框架类的事 件都采用了这种委托类型。例如,Progress 类定义了事件 ProgressChanged,这个事件 的委托类型就是 EventHandler,因此,它就很容易被封装到 FromEventPattern:

1 var  progress = new Progress<int>();
2 var  progressReports = Observable.FromEventPattern<int>(
3 handler => progress.ProgressChanged += handler,
4  handler => progress.ProgressChanged -=  handler);
5 progressReports.Subscribe(data => Trace.WriteLine("OnNext:" + data.EventArgs));

请 注 意,data.EventArgs 是 强 类 型 的 int。FromEventPattern 的 类 型 参 数( 上 例 中 为 int) 与 EventHandler 的 T 相同。Rx 用 FromEventPattern 中的两个 Lambda 参数来实现订阅 和退订事件。

较新的 UI 框架采用 EventHandler,可以很方便地应用在 FromEventPattern 中。但是有 些较旧的类常为每个事件定义不同的委托类型。这些事件也能在 FromEventPattern 中使用, 但需要做一些额外的工作。例如,System.Timers.Timer 类有一个事件 Elapsed,它的类型是 ElapsedEventHandler。对此旧类事件,可以用下面的方法封装进 FromEventPattern:

1 var  timer = new System.Timers.Timer(interval: 1000)
2  {
3  Enabled  = true
4 };
5 var  ticks = Observable.FromEventPattern<ElapsedEventHandler,  ElapsedEventArgs>(
6 handler => (s, a) => handler(s, a),
7 handler => timer.Elapsed += handler,
8 handler => timer.Elapsed -=  handler);
9 ticks.Subscribe(data => Trace.WriteLine("OnNext: "  + data.EventArgs.SignalTime));

注意,data.EventArgs 仍然是强类型的。现在 FromEventPattern 的类型参数是对应的事件 处理程序和 EventArgs 的派生类。FromEventPattern 的第一个 Lambda 参数是一个转换器, 它将 EventHandler 转换成 ElapsedEventHandler。除了传递事件,这个 转换器不应该做其他处理。

上面代码的语法明显有些别扭。另一个方法是使用反射机制:

1 var  timer = new System.Timers.Timer(interval: 1000)  {
2 Enabled  = true
3 }; var  ticks = Observable.FromEventPattern(timer, "Elapsed");
4  ticks.Subscribe(data => Trace.WriteLine("OnNext: "
5 + ((ElapsedEventArgs)data.EventArgs).SignalTime));

采用这种方法后,调用 FromEventPattern 就简单多了。但是这种方法也有缺点:出现了 一个怪异的字符串(”Elapsed”),并且消息的使用者不是强类型了。就是说,这时 data. EventArgs 是 object 类型,需要人为地转换成 ElapsedEventArgs。

讨论
事件是 Rx 流数据的主要来源。本节介绍如何封装遵循标准模式的事件(标准事件模式: 第一个参数是事件发送者,第二个参数是事件的类型参数)。对于不标准的事件类型,可 以用重载 Observable.FromEvent 的办法,把事件封装进 Observable 对象。

把 事 件 封 装 进 Observable 对 象 后, 每 次 引 发 该 事 件 都 会 调 用 OnNext。 在 处 理 AsyncCompletedEventArgs 时 会 发 生 令 人 奇 怪 的 现 象, 所 有 的 异 常 信 息 都 是 通 过 数 据 形 式 传 递 的(OnNext), 而 不 是 通 过 错 误 传 递(OnError)。 看 一 个 封 装 WebClient. DownloadStringCompleted 的例子:

01 var  client = new WebClient();
02 var  downloadedStrings = Observable.FromEventPattern(client, "DownloadStringCompleted");
03 downloadedStrings.Subscribe(
04 data =>
05 {
06 var  eventArgs = (DownloadStringCompletedEventArgs)data.EventArgs;
07 if (eventArgs.Error !=  null)
08 Trace.WriteLine("OnNext: (Error) "  + eventArgs.Error);
09 else
10 Trace.WriteLine("OnNext: "  + eventArgs.Result);
11 },
12 ex  => Trace.WriteLine("OnError: "  + ex.ToString()), () => Trace.WriteLine("OnCompleted"));
13 client.DownloadStringAsync(new Uri("http://invalid.example.com/"));

WebClient.DownloadStringAsync 出错并结束时,引发带有异常 AsyncCompletedEventArgs.Error的事件。可惜 Rx 会把这作为一个数据事件,因此这个程序的结果是显示“OnNext:(Error)”,
而不是“OnError:”。

有些事件的订阅和退订必须在特定的上下文中进行。例如,很多 UI 控件的事件必须在 UI 线程中订阅。Rx 提供了一个操作符 SubscribeOn,可以控制订阅和退订的上下文。大多数 情况下没必要使用这个操作符,因为基于 UI 的事件订阅通常就是在 UI 线程中进行的。

相关文章
|
5月前
|
Go
在golang中发起http请求以获取访问域名的ip地址实例(使用net, httptrace库)
这只是追踪我们的行程的简单方法,不过希望你跟着探险家的脚步,即使是在互联网的隧道中,也可以找到你想去的地方。接下来就是你的探险之旅了,祝你好运!
192 26
|
11月前
|
Java 物联网 C#
C#/.NET/.NET Core学习路线集合,学习不迷路!
C#/.NET/.NET Core学习路线集合,学习不迷路!
415 0
|
6月前
|
SQL 小程序 API
如何运用C#.NET技术快速开发一套掌上医院系统?
本方案基于C#.NET技术快速构建掌上医院系统,结合模块化开发理念与医院信息化需求。核心功能涵盖用户端的预约挂号、在线问诊、报告查询等,以及管理端的排班管理和数据统计。采用.NET Core Web API与uni-app实现前后端分离,支持跨平台小程序开发。数据库选用SQL Server 2012,并通过读写分离与索引优化提升性能。部署方案包括Windows Server与负载均衡设计,确保高可用性。同时针对API差异、数据库老化及高并发等问题制定应对措施,保障系统稳定运行。推荐使用Postman、Redgate等工具辅助开发,提升效率与质量。
201 0
|
10月前
|
开发框架 搜索推荐 算法
一个包含了 50+ C#/.NET编程技巧实战练习教程
一个包含了 50+ C#/.NET编程技巧实战练习教程
268 18
|
10月前
|
缓存 算法 安全
精选10款C#/.NET开发必备类库(含使用教程),工作效率提升利器!
精选10款C#/.NET开发必备类库(含使用教程),工作效率提升利器!
280 12
|
10月前
|
开发框架 人工智能 .NET
C#/.NET/.NET Core拾遗补漏合集(24年12月更新)
C#/.NET/.NET Core拾遗补漏合集(24年12月更新)
134 6
|
10月前
|
开发框架 算法 .NET
C#/.NET/.NET Core技术前沿周刊 | 第 15 期(2024年11.25-11.30)
C#/.NET/.NET Core技术前沿周刊 | 第 15 期(2024年11.25-11.30)
137 6
|
10月前
|
开发框架 Cloud Native .NET
C#/.NET/.NET Core技术前沿周刊 | 第 16 期(2024年12.01-12.08)
C#/.NET/.NET Core技术前沿周刊 | 第 16 期(2024年12.01-12.08)
132 6
|
10月前
|
开发框架 监控 .NET
C#进阶-ASP.NET WebForms调用ASMX的WebService接口
通过本文的介绍,希望您能深入理解并掌握ASP.NET WebForms中调用ASMX WebService接口的方法和技巧,并在实际项目中灵活运用这些技术,提高开发效率和应用性能。
550 5
|
10月前
|
算法 Java 测试技术
Benchmark.NET:让 C# 测试程序性能变得既酷又简单
Benchmark.NET是一款专为 .NET 平台设计的性能基准测试框架,它可以帮助你测量代码的执行时间、内存使用情况等性能指标。它就像是你代码的 "健身教练",帮助你找到瓶颈,优化性能,让你的应用跑得更快、更稳!希望这个小教程能让你在追求高性能的路上越走越远,享受编程带来的无限乐趣!
429 13