许多模型都可以统一至标准的生产者接口IObservable上,如MouseMove事件便可以认做是“永不停止的MouseEventArgs对象的生产者”。而另一方面,单个异步操作则可以被视为“只产出单个数据便结束的生产者”。
LINQ to Observable
在许多人眼中,C# 3.0中新增的LINQ特性只是一种用于操作数据的DSL,它的主要作用也仅仅是针对IEnumerable或是IQueryable的数据操作。
事实上,LINQ本身的能力远不止此。LINQ是一种非常简单的语言特性,编译器只是将LINQ查询语句转化为“字面等价”的“LINQ标准方法”调用(如Where,Select等等)和“和Lambda表达式”参数(如x => x > 0)而已。但是这里的关键便是“字面等价”四个字,LINQ本身并不规定“LINQ标准方法”是对象的实例方法还是扩展方法,“Lambda表达式”是构造出一个匿名函数还是表达式树,这一切都是由利用LINQ的类库来决定的。因此,微软能够基于LINQ实现了PLINQ这样的并行类库。直到最近的访谈中,LINQ的设计者Erik Meijer依旧认为LINQ还是被低估了,他们自己也还在继续挖掘LINQ的更多能力。
虽然LINQ本身在语法上只是一些方法调用,但是它在语义上是针对数据流的一系列操作,因此LINQ to Object,LINQ to SQL以及PLINQ可以认为是最自然,最符合LINQ语义的应用。如今,微软的“云编程能力团队(Cloud Programmability Team)”在其“响应式框架(Reactive Framework,简称Rx)”提供了LINQ to Observable,这又是另一个LINQ的经典使用案例。IObservable本身可以被认为是一股“推送数据”的数据流,因此也可以对其进行“过滤”或是“投影”等操作,这便是LINQ的应用场景,LINQ to Observable是对IObservable接口实现的一系列LINQ标准方法。因此,我们可以认为,LINQ to Observable是一套与LINQ to Object对偶的类库,事实上在响应式框架中,还有一套与LINQ to Queryable对偶的LINQ to Qbservable,请注意第一个字母是Q,我们可以把它看作是LINQ to Observable的“远程查询”版本。
利用LINQ to Object可以编写出声明式(表示“做什么”)的代码,其可读性往往远高于等价的命令式(表示“怎么做”)代码。LINQ to Observable也有类似的效果。假设现在有一个需求:利用ADWS键控制小球的位置。传统的写法可能是这样的:
void OnKeyPress(object sender, KeyPressEventArgs e) { // 如果游戏已经开始 if (isPlaying) { // 向左且小球没有超出边界 if (e.KeyChar == 'a' && ball.Left > 0) { ball.Left -= 5; } // 向上且小球没有超出边界 else if (e.KeyChar == 'w' && ball.Top > 0) { ball.Top -= 5; } else ... } else ... }
由于KeyPress事件总是不断触发,因此我们只能它的事件处理器中进行判断各种状态,采取不同措施。而如果我们利用LINQ to Observable,则几乎是另外一种思维方式:
// 过滤出isPlaying时的keyPress事件 var keyPress = GetKeyPress().Where(_ => isPlaying); // 过滤出向左移动的事件 var moveLeft = from ev in keyPress where ev.EventArgs.KeyChar == 'a' where ball.Left > 0 select ev; moveLeft.Subscribe(_ => ball.Left -= 5); // 过滤出向上移动的事件 var moveTop = from ev in keyPress where ev.EventArgs.KeyChar == 'w' where ball.Top > 0 select ev; moveTop.Subscribe(_ => ball.Top -= 5);
我们可以将“KeyPress事件”视为“推送KeyPressEventArgs对象”这一数据流的数据源(由GetKeyPress方法返回),那么如今的代码便是使用LINQ过滤出“需要”的数据,并针对真正需要的那部分进行响应。这么做,便将“条件”与“操作”解耦,显著增强了代码的语义表达能力。事实上,只要补充一些辅助方法,可以利用LINQ表示更为完整复杂的逻辑。例如,微软咨询师Matthew Podwysocki便在博客中展示过一段代码,基于LINQ to Observable实现了创建一个WebRequest对象,设置属性,异步发送及下载数据的一系列操作。
出处:老赵点滴
责任编辑:bluehearts
上一页 异步编程与响应式框架 [2] 下一页 异步编程与响应式框架 [4]
◎进入论坛网络编程版块参加讨论
|