如何实现带索引参数谓词的List.RemoveAll专用重载?
自定义
List<T>.RemoveAll扩展方法实现需求 List<T>.RemoveAll是一个实用方法,可高效从列表中移除多个元素。但部分场景下,它缺少所需的额外功能,文档也未提供相关保障,且match谓词执行失败时的行为存在问题,因此需要实现一个具备以下特性的扩展方法:
- 接受
Func<T, int, bool>委托而非Predicate<T>,其中int为元素的从零开始索引。 - 保证谓词对每个元素严格按升序仅调用一次。
- 若谓词对部分元素返回
true后执行失败,会先移除已标记为要删除的元素,再抛出异常。
目标扩展方法签名如下:
public static int RemoveAll<T>(this List<T> list, Func<T, int, bool> predicate);
该方法返回被移除元素的数量。
尝试基于官方实现开发,但因性能优化导致复杂度较高,难以注入期望的异常处理逻辑。需要一个简洁且高效的实现,不希望使用LINQ以避免内存分配。
背景:原生方法的异常行为问题
原生List<T>.RemoveAll方法在谓词执行失败时,已标记为删除的元素可能未被移除,或被其他元素副本替代,列表仍保持原大小。以下是演示示例:
List<int> list = new(Enumerable.Range(1, 15)); Console.WriteLine($"Before RemoveAll: [{String.Join(", ", list)}]"); try { list.RemoveAll(item => { if (item == 10) throw new Exception(); bool removeIt = item % 2 == 1; if (removeIt) Console.WriteLine($"Removing #{item}"); return removeIt; }); } catch (Exception ex) { Console.WriteLine(ex); } finally { Console.WriteLine($"After RemoveAll: [{String.Join(", ", list)}]"); }
列表包含15个数字,意图移除奇数,谓词在处理第10个元素时失败。
输出结果:
Before RemoveAll: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] Removing #1 Removing #3 Removing #5 Removing #7 Removing #9 System.Exception: Exception of type 'System.Exception' was thrown. at Program.<>c.<Main>b__0_0(Int32 item) at System.Collections.Generic.List`1.RemoveAll(Predicate`1 match) at Program.Main() After RemoveAll: [2, 4, 6, 8, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
可见1和3被移除,5、7、9仍存在,6和8出现重复。期望的合理输出应为:
After RemoveAll: [2, 4, 6, 8, 10, 11, 12, 13, 14, 15]
这种行为更合理可预测,能降低风险。已向微软反馈该问题,但微软认为失败时结果未定义,不会修改,因此需要自行实现符合需求的方法。
内容的提问来源于stack exchange,提问作者Theodor Zoulias
相关产品推荐
相关产品推荐

