受到另一个关于缺失Zip函数的问题的启发:
为什么在IEnumerable接口上没有ForEach扩展方法?或在任何地方吗?唯一获得ForEach方法的类是List<>。有什么原因吗,也许是性能?
受到另一个关于缺失Zip函数的问题的启发:
为什么在IEnumerable接口上没有ForEach扩展方法?或在任何地方吗?唯一获得ForEach方法的类是List<>。有什么原因吗,也许是性能?
当前回答
我自己也一直在想,这就是为什么我总是带着这个:
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);
}
}
不错的扩展方法。
其他回答
虽然我同意在大多数情况下使用内置的foreach构造更好,但我发现在foreach <>扩展上使用这种变体比自己在常规foreach中管理索引要好一些:
public static int ForEach<T>(this IEnumerable<T> list, Action<int, T> action)
{
if (action == null) throw new ArgumentNullException("action");
var index = 0;
foreach (var elem in list)
action(index++, elem);
return index;
}
Example
var people = new[] { "Moe", "Curly", "Larry" };
people.ForEach((i, p) => Console.WriteLine("Person #{0} is {1}", i, p));
会给你:
Person #0 is Moe
Person #1 is Curly
Person #2 is Larry
你可以这样写扩展方法:
// Possibly call this "Do"
IEnumerable<T> Apply<T> (this IEnumerable<T> source, Action<T> action)
{
foreach (var e in source)
{
action(e);
yield return e;
}
}
Pros
允许链接:
MySequence
.Apply(...)
.Apply(...)
.Apply(...);
Cons
它实际上不会做任何事情,直到你强制迭代。因此,它不应该被称为. foreach()。你可以在结尾写.ToList(),或者你也可以写这个扩展方法:
// possibly call this "Realize"
IEnumerable<T> Done<T> (this IEnumerable<T> source)
{
foreach (var e in source)
{
// do nothing
;
}
return source;
}
这可能与发布的c#库有很大的不同;不熟悉您的扩展方法的读者将不知道如何理解您的代码。
请注意,MoreLINQ NuGet提供了您正在寻找的ForEach扩展方法(以及执行委托并产生结果的Pipe方法)。看到的:
https://www.nuget.org/packages/morelinq https://code.google.com/p/morelinq/wiki/OperatorsOverview
是我还是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/
一种解决方法是编写. tolist()。ForEach(x =>…)
pros
易于理解——读者只需要知道c#附带了什么,而不需要知道任何额外的扩展方法。
语法干扰非常温和(只添加了一点无关的代码)。
通常不需要额外的内存,因为本机. foreach()必须实现整个集合。
cons
操作顺序并不理想。我宁愿实现一个元素,然后付诸行动,然后重复。这段代码首先实现所有元素,然后依次对它们进行操作。
如果意识到列表抛出异常,则永远无法对单个元素进行操作。
如果枚举数是无限的(就像自然数一样),那么你就不走运了。