显然有许多方法可以迭代集合。很好奇是否有什么不同,或者为什么你用一种方式而不是另一种。
第一类型:
List<string> someList = <some way to init>
foreach(string s in someList) {
<process the string>
}
其他方式:
List<string> someList = <some way to init>
someList.ForEach(delegate(string s) {
<process the string>
});
我想,除了我上面使用的匿名委托,你还可以指定一个可重用的委托。
这两者之间有一个重要而有用的区别。
因为.ForEach使用for循环来迭代集合,这是有效的(编辑:在。net 4.5之前-实现改变了,它们都抛出):
someList.ForEach(x => { if(x.RemoveMe) someList.Remove(x); });
而foreach使用枚举数,因此这是无效的:
foreach(var item in someList)
if(item.RemoveMe) someList.Remove(item);
不要复制这段代码到你的应用程序中!
这些示例并不是最佳实践,它们只是为了演示ForEach()和ForEach之间的区别。
在for循环中从列表中删除项可能会产生副作用。最常见的是在这个问题的评论中描述的。
通常,如果希望从列表中删除多个项,则需要将确定要删除哪些项与实际删除分开。它不能使您的代码保持紧凑,但它保证您不会遗漏任何项。
ForEach函数是泛型类List的成员。
我已经创建了以下扩展来复制内部代码:
public static class MyExtension<T>
{
public static void MyForEach(this IEnumerable<T> collection, Action<T> action)
{
foreach (T item in collection)
action.Invoke(item);
}
}
因此,最后我们使用普通的foreach(如果你愿意,也可以使用循环for)。
另一方面,使用委托函数只是定义函数的另一种方式,以下代码:
delegate(string s) {
<process the string>
}
等价于:
private static void myFunction(string s, <other variables...>)
{
<process the string>
}
或者使用labda表达式:
(s) => <process the string>
我知道有两件事让他们不一样。去我!
首先,有一个典型的错误,即为列表中的每个项目创建一个委托。如果你使用foreach关键字,你所有的委托最终都会指向列表的最后一项:
// A list of actions to execute later
List<Action> actions = new List<Action>();
// Numbers 0 to 9
List<int> numbers = Enumerable.Range(0, 10).ToList();
// Store an action that prints each number (WRONG!)
foreach (int number in numbers)
actions.Add(() => Console.WriteLine(number));
// Run the actions, we actually print 10 copies of "9"
foreach (Action action in actions)
action();
// So try again
actions.Clear();
// Store an action that prints each number (RIGHT!)
numbers.ForEach(number =>
actions.Add(() => Console.WriteLine(number)));
// Run the actions
foreach (Action action in actions)
action();
列表中。每个方法都没有这个问题。迭代的当前项按值作为参数传递给外部lambda,然后内部lambda在自己的闭包中正确地捕获该参数。问题解决了。
(遗憾的是,我认为ForEach是List的成员,而不是扩展方法,尽管很容易自己定义它,因此您可以在任何可枚举类型上使用此功能。)
其次,ForEach方法有一定的局限性。如果你通过使用yield return来实现IEnumerable,你不能在lambda中做yield return。因此,通过循环遍历集合中的项以获得返回值是不可能的。您必须使用foreach关键字,并通过手动在循环中复制当前循环值来解决闭包问题。
更多的在这里