如何在IObservable的Scan方法中跳过Null值并维持有效状态
解决Rx中Scan生成Null项的过滤与状态维持问题
你的核心需求是:过滤掉WrapItem返回的null,同时让后续的Item处理时能用上上一个有效的IWrappedItem,避免状态链被无效项打断,且最终的Observable不输出null。
最佳实现方案
不需要替换Scan,它是维护序列状态的最佳工具。我们可以通过让Scan跟踪上一个有效状态和当前是否有可输出的有效项,配合Where过滤无效输出,来实现需求:
IObservable<IWrappedItem> wrappedItems = allItems .Scan( // 初始状态:LastValid为种子项,CurrentOutput初始为null(避免输出种子本身,除非种子有效且需要保留) seed: (LastValid: seedItem, CurrentOutput: (IWrappedItem?)null), accumulator: (state, currentItem) => { var wrapped = WrapItem(currentItem, state.LastValid); // 当前项有效:更新LastValid为新值,标记可输出 if (wrapped != null) { return (LastValid: wrapped, CurrentOutput: wrapped); } // 当前项无效:保留LastValid,标记不可输出 else { return (LastValid: state.LastValid, CurrentOutput: null); } }) // 过滤掉无有效输出的结果 .Where(result => result.CurrentOutput != null) // 提取最终的有效包装项 .Select(result => result.CurrentOutput!);
逻辑说明
- 状态跟踪:
Scan的状态包含两个字段:LastValid:始终记录上一个有效的IWrappedItem,确保后续项处理时不会因为中间无效项丢失状态。CurrentOutput:仅当当前Item被成功包装为有效项时才赋值,否则为null。
- 过滤输出:通过
Where筛掉CurrentOutput为null的结果,确保最终的Observable只输出有效的IWrappedItem。 - 兼容种子项:如果
seedItem为null,只要WrapItem方法能兼容null输入,整个逻辑就可以正常工作,和原有逻辑保持一致。
额外优化(可选)
如果你的业务需要保留初始的seedItem(当它不为null时),可以在序列开头添加一个判断:
var initialValidItem = seedItem != null ? Observable.Return(seedItem) : Observable.Empty<IWrappedItem>(); IObservable<IWrappedItem> wrappedItems = initialValidItem .Concat(allItems.Scan(/* 上述Scan逻辑 */));
内容的提问来源于stack exchange,提问作者Shahar
相关产品推荐
相关产品推荐

