You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现带索引参数谓词的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 01:01:22