在IEnumerable中使用yield return时,无匹配值如何返回默认值?
问题:IEnumerable扩展方法仅在无匹配时返回默认项
我编写了如下C#扩展方法FindAllOccurrence,用于在IEnumerable<T>源中查找特定值的所有匹配项,并返回值与索引。该方法采用yield return实现,而非像List<T>.FindAll()那样返回新集合:
public static class Example { public static IEnumerable<(T sought, int index)> FindAllOccurrence<T>( this IEnumerable<T> source, T value) { if (source == null) throw new ArgumentNullException(nameof(source), "The argument is null"); if (value == null) throw new ArgumentNullException(nameof(value), "The argument is null"); foreach (var pair in source.Select((e, i) => (e, i))) { if (pair.e.Equals(value)) { yield return (pair.e, pair.i); } } // How do I use the if statement here? yield return (default(T), -1); } }
当前存在的问题是,即使存在匹配项,方法末尾的yield return (default(T), -1);语句也会被执行(如下测试代码所示)。我希望仅在没有匹配值时才返回该默认值,请问如何编写合适的条件判断来避免这种情况?
测试代码:
public static void Operation() { var list = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 3, 3, 3 }; var enumerable = list.FindAllOccurrence(3); foreach (var (value, index) in enumerable) { Console.WriteLine($"value: {value}, index: {index}"); } }
解决方案
核心思路是添加一个布尔标记,记录遍历过程中是否找到过匹配项。遍历结束后,仅当标记为false时才返回默认项。修改后的代码如下:
public static class Example { public static IEnumerable<(T sought, int index)> FindAllOccurrence<T>( this IEnumerable<T> source, T value) { if (source == null) throw new ArgumentNullException(nameof(source), "The argument is null"); if (value == null) throw new ArgumentNullException(nameof(value), "The argument is null"); bool found = false; // 标记是否找到匹配项 foreach (var pair in source.Select((e, i) => (e, i))) { if (pair.e.Equals(value)) { found = true; yield return (pair.e, pair.i); } } // 仅当无匹配时返回默认项 if (!found) { yield return (default(T), -1); } } }
关键说明:
- 新增
bool found = false;变量,初始状态为未找到匹配。 - 每次找到匹配项并
yield return时,将found设为true。 - 遍历完成后,通过
if (!found)判断,仅在无任何匹配时才返回(default(T), -1)。
测试效果:
- 当原测试代码运行时,只会输出所有匹配的项(索引2、10、11、12对应的3),不会再出现末尾的默认项。
- 如果传入的列表中没有目标值,比如
var list = new List<int>{1,2,4};,则会输出value: 0, index: -1(int的default值为0)。
内容的提问来源于stack exchange,提问作者na_sacc
相关产品推荐
相关产品推荐

