如何在LINQ中实现首次Where无结果时执行第二次Where筛选?
实现LINQ"无结果时切换筛选条件"的链式调用
要实现你需求的逻辑——先用第一个条件筛选,无结果时再用第二个条件筛选,且保持单个LINQ查询的链式风格——LINQ本身没有内置方法,但可以通过自定义扩展方法轻松实现,不用拆成if语句。
方案1:双条件扩展方法(最推荐)
这是最直接简洁的写法,扩展方法直接接收两个筛选条件,内部处理"先试第一个,无结果再用第二个"的逻辑:
public static class EnumerableExtensions { public static IEnumerable<T> WhereOrFallback<T>(this IEnumerable<T> source, Func<T, bool> primaryCondition, Func<T, bool> fallbackCondition) { // 缓存第一个条件的结果,避免多次遍历原序列 var primaryResults = source.Where(primaryCondition).ToList(); return primaryResults.Any() ? primaryResults : source.Where(fallbackCondition); } }
调用时直接链式调用,完全符合你想要的"单个LINQ查询"形式:
return list.WhereOrFallback(item => condition1, item => condition2).ToList();
方案2:贴近你伪代码的链式写法
如果你坚持想要Where(...).IfNoResultsWhere(...)的语法风格,可以通过扩展方法+辅助类实现。需要注意的是,Where(condition1)返回的是筛选后的序列,我们需要让IfNoResultsWhere能访问原序列,所以封装一个辅助类来保存上下文:
public static class EnumerableExtensions { public static FallbackQuery<T> WhereWithFallback<T>(this IEnumerable<T> source, Func<T, bool> primaryCondition) { var primaryResults = source.Where(primaryCondition).ToList(); return new FallbackQuery<T>(source, primaryResults); } } public class FallbackQuery<T> { private readonly IEnumerable<T> _originalList; private readonly List<T> _primaryResults; public FallbackQuery(IEnumerable<T> originalList, List<T> primaryResults) { _originalList = originalList; _primaryResults = primaryResults; } public IEnumerable<T> IfNoResultsWhere(Func<T, bool> fallbackCondition) { return _primaryResults.Any() ? _primaryResults : _originalList.Where(fallbackCondition); } }
调用方式就和你写的伪代码几乎一致了:
return list.WhereWithFallback(item => condition1).IfNoResultsWhere(item => condition2).ToList();
重要提示
两种方案都用到了ToList()提前枚举并缓存结果,这是为了避免LINQ延迟执行导致的多次遍历原序列,提升性能——如果不缓存,判断Any()和最终返回结果时会分别遍历一次,浪费资源。
内容的提问来源于stack exchange,提问作者Yoda
相关产品推荐
相关产品推荐

