昨天,我观看了编写您的第一个 Rx 应用程序(在第 9 频道)的截屏视频,其中 Wes Dyer 展示了如何使用响应式扩展 (Rx)实现 Drag 'n' Drop 。我仍然不明白的东西:
在截屏视频快结束时,韦斯·戴尔键入以下内容:
var q = from start in mouseDown
from delta in mouseMove.StartsWith(start).Until(mouseUp)
.Let(mm => mm.Zip(mm.Skip(1), (prev, cur) =>
new { X = cur.X - prev.X, Y = cur.Y - prev.Y }))
select delta;
简而言之,q
是一个将鼠标移动坐标增量推送给其订阅者的 observable。
我不明白的是怎么mm.Zip(mm.Skip(1), ...)
可能工作!?
据我所知,IObservable
在这个意义上是不可枚举的IEnumerable
。由于 的“拉”性质IEnumerable
,它可以一次又一次地迭代,总是产生相同的项目。(至少所有表现良好的枚举都应该是这种情况。)IObservable
工作方式不同。项目被推送给订阅者一次,就是这样。在上面的例子中,鼠标移动是单个事件,如果没有记录在内存中就不能重复。
那么,.Zip
与.Skip(1)
可能的组合如何工作,因为他们正在处理的鼠标事件是单一的、不可重复的事件?这个操作不需要mm
独立“查看”两次吗?
作为参考,以下是 的方法签名Observable.Zip
:
public static IObservable<TResult> Zip <TLeft, TRight, TResult>
(
this IObservable<TLeft> leftSource, // = mm
IObservable<TRight> rightSource, // = mm.Skip(1)
Func<TLeft, TRight, TResult> selector
)