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

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


当前回答

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

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

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

其他回答

您可以使用(可链的,但延迟计算)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,但懒惰和可链。

@Coincoin

foreach扩展方法的真正功能包括Action<>的可重用性,而无需向代码添加不必要的方法。假设您有10个列表,并且您希望对它们执行相同的逻辑,而对应的函数不适合您的类并且不能重用。您可以将所有逻辑保存在一个地方,而不是使用十个for循环,或者使用一个显然不属于helper的通用函数(Action<>。所以,很多行被替换成

Action<blah,blah> f = { foo };

List1.ForEach(p => f(p))
List2.ForEach(p => f(p))

等等……

逻辑是在一个地方,你没有污染你的课。

请注意,MoreLINQ NuGet提供了您正在寻找的ForEach扩展方法(以及执行委托并产生结果的Pipe方法)。看到的:

https://www.nuget.org/packages/morelinq https://code.google.com/p/morelinq/wiki/OperatorsOverview

当你想要返回一些东西时,你可以使用select。 如果不需要,可以先使用ToList,因为您可能不想修改集合中的任何内容。

在3.5中,所有添加到IEnumerable中的扩展方法都是为了支持LINQ(注意它们是在System.Linq.Enumerable类中定义的)。在这篇文章中,我解释了为什么foreach不属于LINQ: 现有的LINQ扩展方法类似于Parallel.For?