c# – 获取IObservable中的上一个元素,而无需重新评估序列

在一个IObservable序列中(在.NET的Reactive Extensions中),我想获取以前和当前元素的值,以便我们可以比较它们.我发现一个类似下面的在线示例完成任务:

sequence.Zip(sequence.Skip(1), (prev, cur) => new { Previous = prev, Current = cur })

它工作正常,除了它评估序列两次,我想避免.你可以看到这个代码被评估了两次:

var debugSequence = sequence.Do(item => Debug.WriteLine("Retrieved an element from sequence"));
debugSequence.Zip(debugSequence.Skip(1), (prev, cur) => new { Previous = prev, Current = cur }).Subscribe();

输出显示的次数是序列中元素的两倍.

我明白为什么会发生这种情况,但到目前为止,我还没有找到一个不能对序列进行评估的替代方法.如何组合以前和当前只有一个序列评估?

有一个更好的解决方案,我认为,它使用Observable.Scan并避免双重订阅:

public static IObservable<Tuple<TSource, TSource>>
    PairWithPrevious<TSource>(this IObservable<TSource> source)
{
    return source.Scan(
        Tuple.Create(default(TSource), default(TSource)),
        (acc, current) => Tuple.Create(acc.Item2, current));
}

我在这里写了我的博客:http://www.zerobugbuild.com/?p=213

附录

进一步的修改允许您使用结果选择器更干净地处理任意类型:

public static IObservable<TResult> CombineWithPrevious<TSource,TResult>(
    this IObservable<TSource> source,
    Func<TSource, TSource, TResult> resultSelector)
{
    return source.Scan(
        Tuple.Create(default(TSource), default(TSource)),
        (previous, current) => Tuple.Create(previous.Item2, current))
        .Select(t => resultSelector(t.Item1, t.Item2));
}
相关文章
相关标签/搜索