C#为什么 IEnumerable 没有提供 ForEach ?

咨询区

  • Cameron MacFarland

为什么 IEnumerable 接口没有 ForEach 扩展方法?我观察到能获取 ForEach 方法的类是 List<>,有谁知道这么设计的原因吗,是为了性能?

回答区

  • aku

ForEach 方法其实在 Linq 之前就已经存在了,如果这时候在 IEnumerable 上添加 ForEach 扩展方法的话会出现什么结果呢?大家应该知道扩展方法的优先级是低于同名的非扩展方法,这就意味着 IEnumerable 下的 ForEach 永远得不到调用。.

如果你真的想要这个功能,可以自己实现一个。

public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
    foreach (T element in source) 
        action(element);
}


  • leppie

大多数 Linq 扩展方法都会返回 result,但 ForEach 这种不返回的扩展方法并不适合在这种模式中。


  • Martijn

你可以使用链式延迟的 Select 来替换 ForEach, 比如下面这样。

IEnumerable<string> people = new List<string>(){"alica", "bob", "john", "pete"};
people.Select(p => { Console.WriteLine(p); return p; });

如果要立即执行的话,可以再调用 Count(),据我所知这是触发迭代最小代价的方法,当然你可以调用你需要的立即执行方法。

不过我倒希望下面的扩展方法被引入到标准类库中。

static IEnumerable<T> WithLazySideEffect(this IEnumerable<T> src, Action<T> action) {
  return src.Select(i => { action(i); return i; } );
}

上面的代码等价于 foreach,不过是链式延迟的。

点评区

Linq 不提供 ForEach 扩展方法,我感觉是设计者故意为之的,Linq 的一个强大特性在于可链式,可延迟,它和 ForEach 中间还差了一个 ToList,也许手工 ToList 可以让代码意图更明显吧,比如:

        static void Main(string[] args)
        {
            IEnumerable<Person> list = new List<Person>();

            list.Where(v => v.Name == "xxx").ToList().ForEach(m => Console.WriteLine(m.Name));
        }

当然你不认同这种理念也没关系,很多的 Linq 扩展库也不认同,它们就直接提供了 ForEach,比如:MoreLinq   https://github.com/morelinq/