Rx.NET中Scan无resultSelector重载原因及自定义实现方法
设计原因
Aggregate和Scan的核心行为差异决定了API设计的区别:
Aggregate仅会在源序列完成时,输出唯一的最终累加结果,resultSelector只需要执行一次,用来把最终累加值转换为目标类型,符合Aggregate单次输出的语义,也和LINQ原生的Aggregate重载设计保持一致。Scan是每收到一个源元素就输出当前的累加结果,属于连续多输出的操作符。Rx.NET团队没有提供带resultSelector的重载,是因为直接调用Scan(seed, accumulator).Select(resultSelector)就可以完全实现相同效果,不需要额外增加API的维护成本和理解成本。
自定义Scan操作符实现
你要求的签名可以通过封装原生操作符快速实现,这种方式复用了Rx.NET内置的线程安全、生命周期管理、错误处理逻辑,是最稳妥的实现方案:
using System; using System.Reactive.Linq; public static class ObservableExtensions { public static IObservable<TResult> Scan<TSource, TAccumulate, TResult>( this IObservable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> accumulator, Func<TAccumulate, TResult> resultSelector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (accumulator == null) throw new ArgumentNullException(nameof(accumulator)); if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector)); return source.Scan(seed, accumulator).Select(resultSelector); } }
使用示例
以下代码演示了每次接收数字后输出累加和的两倍值:
// 生成1-5的序列 var numberSource = Observable.Range(1, 5); numberSource.Scan( seed: 0, accumulator: (sum, current) => sum + current, resultSelector: total => $"当前累加和的两倍为:{total * 2}" ) .Subscribe(Console.WriteLine);
运行输出如下:
当前累加和的两倍为:2 当前累加和的两倍为:6 当前累加和的两倍为:12 当前累加和的两倍为:20 当前累加和的两倍为:30
内容的提问来源于stack exchange,提问作者jack
相关产品推荐
相关产品推荐

