受到另一个关于缺失Zip函数的问题的启发:
为什么在IEnumerable接口上没有ForEach扩展方法?或在任何地方吗?唯一获得ForEach方法的类是List<>。有什么原因吗,也许是性能?
受到另一个关于缺失Zip函数的问题的启发:
为什么在IEnumerable接口上没有ForEach扩展方法?或在任何地方吗?唯一获得ForEach方法的类是List<>。有什么原因吗,也许是性能?
当前回答
如果你有f#(它将在。net的下一个版本中),你可以使用
Seq。iter doSomething myIEnumerable
其他回答
部分原因是语言设计者从哲学角度不同意这一观点。
没有(和测试……)一个功能比有一个功能更省事。 它并不是真的更短(有一些传递函数的情况下,它是,但这不是主要用途)。 它的目的是产生副作用,这不是linq的目的。 为什么要用另一种方式来做我们已经拥有的功能呢?(为每一个关键字)
https://blogs.msdn.microsoft.com/ericlippert/2009/05/18/foreach-vs-foreach/
您可以使用(可链的,但延迟计算)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,但懒惰和可链。
我想对Aku的回答进行进一步阐述。
如果你想调用一个方法的唯一目的是它的副作用,而不是首先迭代整个枚举对象,你可以使用这个:
private static IEnumerable<T> ForEach<T>(IEnumerable<T> xs, Action<T> f) {
foreach (var x in xs) {
f(x); yield return x;
}
}
是我还是List<T>。Foreach几乎被Linq淘汰了。 最初有
foreach(X x in Y)
其中Y必须是IEnumerable (Pre 2.0),并实现GetEnumerator()。 如果您查看生成的MSIL,您可以看到它与
IEnumerator<int> enumerator = list.GetEnumerator();
while (enumerator.MoveNext())
{
int i = enumerator.Current;
Console.WriteLine(i);
}
(MSIL见http://alski.net/post/0a-for-foreach-forFirst-forLast0a-0a-.aspx)
然后在DotNet2.0中出现了泛型和列表。我一直觉得Foreach是访问者模式的实现(参见Gamma, Helm, Johnson, Vlissides的设计模式)。
当然,在3.5中,我们可以使用Lambda来达到同样的效果,举个例子 http://dotnet-developments.blogs.techtarget.com/2008/09/02/iterators-lambda-and-linq-oh-my/
我自己也一直在想,这就是为什么我总是带着这个:
public static void ForEach<T>(this IEnumerable<T> col, Action<T> action)
{
if (action == null)
{
throw new ArgumentNullException("action");
}
foreach (var item in col)
{
action(item);
}
}
不错的扩展方法。