【问题标题】:How does the List<T>.ForEach(Action<T> action) method actually work?List<T>.ForEach(Action<T> action) 方法实际上是如何工作的?
【发布时间】:2021-12-04 15:33:17
【问题描述】:

我查看了 List.ForEach(Action action) 方法的文档,但它只说明了它的作用,而不是它的作用。我知道它会采取行动并对列表的所有元素执行该行动。但是它用来完成此操作的实际代码是什么?有没有一种方法可以让我自己的 ForEach 方法与列表 ForEach 方法的工作方式相同?

过去我曾想压缩我的 ForEach 循环,这看起来在某些情况下效果很好,尤其是当我使用自定义类时。

【问题讨论】:

  • 一个普通的foreach 语句接受一个IEnumerable(如果它是一个泛型集合,则为泛型版本)并在其上调用GetEnumerator,返回一个IEnumerator(可能是of T)。然后它使用枚举器遍历集合。 List&lt;T&gt;.ForEach 方法是一种扩展方法,它遍历列表(使用简单的foreach)并在列表的每个成员上调用给定的Action&lt;T&gt;。写起来很简单(只需在列表类上写一个扩展方法来完成我所描述的操作。那里没有魔法
  • @Flydog57 C# 还支持将foreach 与具有GetEnumerator() 方法的任何对象 一起使用——类型不再需要实现IEnumerable。这样做是为了支持值类型集合,而无需对接口进行装箱。 stackoverflow.com/questions/21486382/…
  • @dai:C# 还对非泛型集合进行了特殊处理,提供了一种进行类型安全枚举的方法,即使非泛型 IEnumerator 方法仅适用于 objects。这是在 v1.0 和 v1.1 时代(在 v2.0 中引入泛型之前)实现的,因此程序员不必在 foreach 循环中进行强制转换
  • @Flydog57 呃,与您建议的程度不同。 foreach 语句仍然在 C# 7、8 中执行不安全强制转换,我认为 9 也是。

标签: c# list methods foreach


【解决方案1】:

我将从 c# 源代码中提取 if,即 published online on a dedicated site at MSalso on GitHub - 用于收藏的有用资源:

 public void ForEach(Action<T> action) {
        if( action == null) {
            ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
        }
        Contract.EndContractBlock();

        int version = _version;

        for(int i = 0 ; i < _size; i++) {
            if (version != _version && BinaryCompatibility.TargetsAtLeast_Desktop_V4_5) {
                break;
            }
            action(_items[i]);
        }

        if (version != _version && BinaryCompatibility.TargetsAtLeast_Desktop_V4_5)
            ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
    }

大多数情况下它只是用于版本检查和抛出的绒毛,核心部分是一个 for 循环,它采用您提供的方法并在每个列表项中依次调用它:

    public void ForEach(Action<T> action) {

        for(int i = 0 ; i < _size; i++) {
            action(_items[i]);
        }

    }

您绝对可以在自己的课程中自己编写它,它看起来就像那样。这是 .NET 框架版本 - 核心版本不会有太大不同

请注意,这不是一个巨大的字符节省:

foreach(var v in vList) myMethod(v);
vList.ForEach(myMethod);

foreach(var v in vList)
  if(v.X > 10)
    Console.WriteLine(v.Y);

vList.ForEach(v => {
  if(v.X > 10)
    Console.WriteLine(v.Y);
});

随着 foreach 变得越来越长,对于大多数人来说,它仍然具有相当的可读性,而当您开始使用多行 lambda 时,它们最终可能会看起来更加凌乱,而且不会更加简洁

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-04
    • 1970-01-01
    • 1970-01-01
    • 2013-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多