受到另一个关于缺失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扩展方法不合适的评论,因为它不像LINQ扩展方法那样返回值。虽然这是事实陈述,但并不完全正确。
LINQ扩展方法都返回一个值,所以它们可以链接在一起:
collection.Where(i => i.Name = "hello").Select(i => i.FullName);
然而,仅仅因为LINQ是使用扩展方法实现的,并不意味着扩展方法必须以相同的方式使用并返回一个值。编写一个扩展方法来公开不返回值的常见功能是完全有效的使用。
关于ForEach的具体参数是,基于扩展方法的约束(即扩展方法永远不会覆盖具有相同签名的继承方法),可能存在这样一种情况,即自定义扩展方法在所有impelement IEnumerable<T> (List<T>除外)的类上可用。这可能会导致混淆,因为根据调用的是扩展方法还是继承方法,方法开始表现不同。
大多数LINQ扩展方法都返回结果。ForEach不符合这个模式,因为它什么也不返回。
ForEach方法在LINQ之前添加。如果您添加ForEach扩展,由于扩展方法的约束,它将永远不会被用于List实例。我认为没有添加的原因是为了不干扰现有的。
但是,如果您真的错过了这个漂亮的小函数,您可以推出自己的版本
public static void ForEach<T>(
this IEnumerable<T> source,
Action<T> action)
{
foreach (T element in source)
action(element);
}
还没有人指出ForEach<T>导致编译时类型检查,其中ForEach关键字是运行时检查的。
在代码中使用了这两个方法之后,我做了一些重构,我倾向于. foreach,因为我必须查找测试失败/运行时失败来找到foreach问题。
是我还是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/