受到另一个关于缺失Zip函数的问题的启发:

为什么在IEnumerable接口上没有ForEach扩展方法?或在任何地方吗?唯一获得ForEach方法的类是List<>。有什么原因吗,也许是性能?


当前回答

我为此写了一篇博文: http://blogs.msdn.com/kirillosenkov/archive/2009/01/31/foreach.aspx

如果你想在。net 4.0中看到这个方法,你可以在这里投票: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=279093

其他回答

您可以使用(可链的,但延迟计算)Select,首先执行操作,然后返回标识(如果您愿意,也可以返回其他内容)

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

您需要确保它仍然被求值,可以使用Count()(枚举afaik最便宜的操作),也可以使用其他您需要的操作。

不过,我希望看到它被引入标准库:

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

上面的代码就变成了人。WithLazySideEffect(p => Console.WriteLine(p)),这实际上相当于foreach,但懒惰和可链。

部分原因是语言设计者从哲学角度不同意这一观点。

没有(和测试……)一个功能比有一个功能更省事。 它并不是真的更短(有一些传递函数的情况下,它是,但这不是主要用途)。 它的目的是产生副作用,这不是linq的目的。 为什么要用另一种方式来做我们已经拥有的功能呢?(为每一个关键字)

https://blogs.msdn.microsoft.com/ericlippert/2009/05/18/foreach-vs-foreach/

大多数LINQ扩展方法都返回结果。ForEach不符合这个模式,因为它什么也不返回。

如果你有f#(它将在。net的下一个版本中),你可以使用

Seq。iter doSomething myIEnumerable

我想对Aku的回答进行进一步阐述。

如果你想调用一个方法的唯一目的是它的副作用,而不是首先迭代整个枚举对象,你可以使用这个:

private static IEnumerable<T> ForEach<T>(IEnumerable<T> xs, Action<T> f) {
    foreach (var x in xs) {
        f(x); yield return x;
    }
}