受到另一个关于缺失Zip函数的问题的启发:
为什么在IEnumerable接口上没有ForEach扩展方法?或在任何地方吗?唯一获得ForEach方法的类是List<>。有什么原因吗,也许是性能?
受到另一个关于缺失Zip函数的问题的启发:
为什么在IEnumerable接口上没有ForEach扩展方法?或在任何地方吗?唯一获得ForEach方法的类是List<>。有什么原因吗,也许是性能?
当前回答
在该语言中已经包含了一个foreach语句,它在大多数情况下都可以完成这项工作。
我不希望看到以下情况:
list.ForEach( item =>
{
item.DoSomething();
} );
而不是:
foreach(Item item in list)
{
item.DoSomething();
}
后者在大多数情况下更清晰,更容易阅读,尽管可能要长一点打字。
然而,我必须承认我在这个问题上改变了立场;ForEach()扩展方法在某些情况下确实很有用。
下面是语句和方法之间的主要区别:
类型检查:foreach在运行时完成,foreach()在编译时完成(大加分!) 调用委托的语法确实简单得多:objects.ForEach(DoSomething); ForEach()可以被链接:尽管这样一个特性的邪恶/有用还有待讨论。
这些都是很多人提出的很好的观点,我可以理解为什么人们忽略了这个功能。我不介意微软在下一个框架迭代中添加标准ForEach方法。
其他回答
因此,有很多关于ForEach扩展方法不合适的评论,因为它不像LINQ扩展方法那样返回值。虽然这是事实陈述,但并不完全正确。
LINQ扩展方法都返回一个值,所以它们可以链接在一起:
collection.Where(i => i.Name = "hello").Select(i => i.FullName);
然而,仅仅因为LINQ是使用扩展方法实现的,并不意味着扩展方法必须以相同的方式使用并返回一个值。编写一个扩展方法来公开不返回值的常见功能是完全有效的使用。
关于ForEach的具体参数是,基于扩展方法的约束(即扩展方法永远不会覆盖具有相同签名的继承方法),可能存在这样一种情况,即自定义扩展方法在所有impelement IEnumerable<T> (List<T>除外)的类上可用。这可能会导致混淆,因为根据调用的是扩展方法还是继承方法,方法开始表现不同。
在该语言中已经包含了一个foreach语句,它在大多数情况下都可以完成这项工作。
我不希望看到以下情况:
list.ForEach( item =>
{
item.DoSomething();
} );
而不是:
foreach(Item item in list)
{
item.DoSomething();
}
后者在大多数情况下更清晰,更容易阅读,尽管可能要长一点打字。
然而,我必须承认我在这个问题上改变了立场;ForEach()扩展方法在某些情况下确实很有用。
下面是语句和方法之间的主要区别:
类型检查:foreach在运行时完成,foreach()在编译时完成(大加分!) 调用委托的语法确实简单得多:objects.ForEach(DoSomething); ForEach()可以被链接:尽管这样一个特性的邪恶/有用还有待讨论。
这些都是很多人提出的很好的观点,我可以理解为什么人们忽略了这个功能。我不介意微软在下一个框架迭代中添加标准ForEach方法。
我想对Aku的回答进行进一步阐述。
如果你想调用一个方法的唯一目的是它的副作用,而不是首先迭代整个枚举对象,你可以使用这个:
private static IEnumerable<T> ForEach<T>(IEnumerable<T> xs, Action<T> f) {
foreach (var x in xs) {
f(x); yield return x;
}
}
如果你有f#(它将在。net的下一个版本中),你可以使用
Seq。iter doSomething myIEnumerable
虽然我同意在大多数情况下使用内置的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