显然有许多方法可以迭代集合。很好奇是否有什么不同,或者为什么你用一种方式而不是另一种。

第一类型:

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作用域(委托函数)被视为一行代码(调用该函数),您不能设置断点或进入代码。如果发生未处理的异常,则标记整个块。

其他回答

我知道有两件事让他们不一样。去我!

首先,有一个典型的错误,即为列表中的每个项目创建一个委托。如果你使用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关键字,并通过手动在循环中复制当前循环值来解决闭包问题。

更多的在这里

List.ForEach()被认为更具功能性。

List.ForEach()表示你想做什么。Foreach(列表中的项目)也确切地说明了你想要如何完成它。这就剩下List了。ForEach可以自由更改未来如何部分的实现。例如,一个假设的。net未来版本可能总是运行List。在并行的情况下,假设此时每个人都有一些cpu核心通常处于空闲状态。

另一方面,foreach (list中的项)让您对循环有更多的控制。例如,您知道项目将以某种顺序进行迭代,如果项目满足某些条件,则很容易在中间中断。


关于这个问题的一些最新评论可在此查阅:

https://stackoverflow.com/a/529197/3043

这两者之间有一个重要而有用的区别。

因为.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循环中从列表中删除项可能会产生副作用。最常见的是在这个问题的评论中描述的。

通常,如果希望从列表中删除多个项,则需要将确定要删除哪些项与实际删除分开。它不能使您的代码保持紧凑,但它保证您不会遗漏任何项。

我们这里有一些代码(在VS2005和c# 2.0中),以前的工程师用他们的方式使用列表。ForEach(delegate(item) {foo;});而不是foreach(item in list) {foo;};他们写的所有代码。例如,从dataReader读取行的代码块。

我还是不知道他们为什么要这么做。

list.ForEach()的缺点是:

It is more verbose in C# 2.0. However, in C# 3 onwards, you can use the "=>" syntax to make some nicely terse expressions. It is less familiar. People who have to maintain this code will wonder why you did it that way. It took me awhile to decide that there wasn't any reason, except maybe to make the writer seem clever (the quality of the rest of the code undermined that). It was also less readable, with the "})" at the end of the delegate code block. See also Bill Wagner's book "Effective C#: 50 Specific Ways to Improve Your C#" where he talks about why foreach is preferred to other loops like for or while loops - the main point is that you are letting the compiler decide the best way to construct the loop. If a future version of the compiler manages to use a faster technique, then you will get this for free by using foreach and rebuilding, rather than changing your code. a foreach(item in list) construct allows you to use break or continue if you need to exit the iteration or the loop. But you cannot alter the list inside a foreach loop.

看到这个名单我很惊讶。ForEach稍微快一点。但这可能不是贯穿始终的有效理由,那将是不成熟的优化。如果你的应用程序使用的是数据库或web服务,而不是循环控制,那么时间几乎总是会花在那里。你也用for循环测试过它吗?列表中。ForEach可以更快,因为在内部使用它,没有包装器的for循环甚至更快。

我不同意list.ForEach(委托)版本在任何重要方面都“更实用”。它确实将一个函数传递给另一个函数,但在结果或程序组织方面没有太大的区别。

我不认为每一项都是这样。“确切地说你想怎么做”- a for(int 1 = 0;I < count;i++)循环可以做到这一点,foreach循环将控制的选择留给编译器。

My feeling is, on a new project, to use foreach(item in list) for most loops in order to adhere to the common usage and for readability, and use list.Foreach() only for short blocks, when you can do something more elegantly or compactly with the C# 3 "=>" operator. In cases like that, there may already be a LINQ extension method that is more specific than ForEach(). See if Where(), Select(), Any(), All(), Max() or one of the many other LINQ methods doesn't already do what you want from the loop.

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>