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

List<T>.ForEach(Action<T> action)方法运行原理是什么?如何自行实现同款功能?

List.ForEach 底层实现与自定义实现方案

官方底层实现逻辑

.NET 官方List<T>.ForEach的核心实现代码如下(基于.NET 7 源码简化):

public void ForEach(Action<T> action)
{
    // 入参非空校验
    if (action == null)
    {
        throw new ArgumentNullException(nameof(action));
    }

    // 记录集合初始版本号,每次修改集合(增删改元素)都会更新该值
    int originalVersion = _version;
    // 遍历内部存储数组的有效元素
    for (int i = 0; i < _size; i++)
    {
        // 遍历中途检测到集合被修改,终止遍历
        if (originalVersion != _version)
        {
            break;
        }
        // 对当前元素执行传入的委托
        action(_items[i]);
    }

    // 最终校验集合版本,被修改则抛出异常
    if (originalVersion != _version)
    {
        throw new InvalidOperationException("集合已被修改,枚举操作无法继续执行。");
    }
}

其中三个内部字段的作用:

  • _items:List内部用来存储元素的数组
  • _size:List当前实际存储的元素数量,和Count属性返回值一致
  • _version:集合版本号,每次调用Add/Remove/Insert/Clear等修改集合的方法时都会自增,用来检测遍历过程中的集合修改行为。

完全对齐官方行为的自定义实现

如果需要自定义和官方功能完全一致的ForEach方法,分两种场景处理:

场景1:自定义集合类内置ForEach

直接在自己的集合类中维护_items、_size、_version三个字段,每次修改集合时更新_version,直接套用上面的官方实现代码即可,性能和官方实现完全一致,非常适合自定义类的使用场景。

场景2:给官方List写扩展方法

需要用反射获取List的内部字段,实现代码如下:

public static class ListExtensions
{
    public static void CustomForEach<T>(this List<T> list, Action<T> action)
    {
        if (list == null) throw new ArgumentNullException(nameof(list));
        if (action == null) throw new ArgumentNullException(nameof(action));

        // 反射获取内部字段
        var versionField = typeof(List<T>).GetField("_version", 
            System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
        var itemsField = typeof(List<T>).GetField("_items", 
            System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
        
        int originalVersion = (int)versionField.GetValue(list);
        T[] items = (T[])itemsField.GetValue(list);
        int count = list.Count;

        for (int i = 0; i < count; i++)
        {
            if ((int)versionField.GetValue(list) != originalVersion)
                throw new InvalidOperationException("集合已被修改,枚举操作无法继续执行。");
            action(items[i]);
        }

        if ((int)versionField.GetValue(list) != originalVersion)
            throw new InvalidOperationException("集合已被修改,枚举操作无法继续执行。");
    }
}

如果不需要严格对齐官方的集合修改校验逻辑,只需要简化循环写法,可以用更通用的IEnumerable扩展方法,适配所有可枚举类型,性能损失更小:

public static class EnumerableExtensions
{
    public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
    {
        if (source == null) throw new ArgumentNullException(nameof(source));
        if (action == null) throw new ArgumentNullException(nameof(action));
        
        foreach (var item in source)
        {
            action(item);
        }
    }
}

内容的提问来源于stack exchange,提问作者Exogenex

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 16:27:01