foreach vs someList.ForEach(){}

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

第一类:

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);

tl; dr:不要将此代码复制到您的应用程序中!

这些例子并不是最佳实践,它们仅仅是为了展示ForEach()foreach之间的区别。

for循环中的列表中删除项目可能会产生副作用。 在这个问题的评论中描述了最常见的一个。

一般来说,如果您正在寻找从列表中删除多个项目,您希望将确定哪些项目从实际删除中删除。 它不会让你的代码紧凑,但它保证你不会错过任何项目。


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

我仍然不知道他们为什么这样做。

list.ForEach()的缺点是:

  • 它在C#2.0中更加冗长。 但是,在C#3以后,可以使用“ => ”语法来制作一些很好的简洁表达式。

  • 它不太熟悉。 必须维护这些代码的人会想知道为什么你这样做。 我花了一段时间才决定没有任何理由,除了让作者看起来很聪明(其他代码的质量破坏了这一点)。 它的可读性也较差,“ }) ”在委托代码块的末尾。

  • 另请参阅Bill Wagner的书“Effective C#:50 Specific Ways to Improve Your C#”,他谈到了为什么foreach比其他循环更喜欢for或while循环 - 主要的一点是让编译器决定构建最佳方式循环。 如果未来版本的编译器设法使用更快的技术,那么您将通过使用foreach和重建来免费获得此版本,而不是更改您的代码。

  • 如果您需要退出迭代或循环,则foreach(item in list)构造允许您使用breakcontinue 。 但是你不能在foreach循环内改变列表。

  • 我很惊讶地看到list.ForEach稍快。 但是这可能不是一个有效的使用它的理由,那将是不成熟的优化。 如果您的应用程序使用数据库或Web服务,而不是循环控制,则几乎总是会随时间推移。 你有没有将它与for循环进行比较? list.ForEach可能因为内部使用而更快,而没有包装的for循环会更快。

    我不同意list.ForEach(delegate)版本以任何重要方式“更实用”。 它将函数传递给函数,但结果或程序组织没有太大差异。

    我不认为foreach(item in list) “确切地说明了你想如何完成” - a for(int 1 = 0; i < count; i++)循环会这样做, foreach循环会将控制权选择为编译器。

    我的感觉是,在一个新项目中,为了遵守常见用法和可读性,在大多数循环中使用foreach(item in list) ,并且只使用list.Foreach()仅用于短块,当你可以做更多的事情时优雅地或紧凑地与C#3“ => ”运营商。 在这种情况下,可能已经存在比ForEach()更具体的LINQ扩展方法。 看看Where()Select()Any()All()Max()或其他许多LINQ方法之一是否还没有做到你想要的循环。


    为了好玩,我将List弹出到了反射器中,这是由此产生的C#:

    public void ForEach(Action<T> action)
    {
        if (action == null)
        {
            ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
        }
        for (int i = 0; i < this._size; i++)
        {
            action(this._items[i]);
        }
    }
    

    同样,在foreach中使用的Enumerator中的MoveNext是这样的:

    public bool MoveNext()
    {
        if (this.version != this.list._version)
        {
            ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
        }
        if (this.index < this.list._size)
        {
            this.current = this.list._items[this.index];
            this.index++;
            return true;
        }
        this.index = this.list._size + 1;
        this.current = default(T);
        return false;
    }
    

    List.ForEach比MoveNext更精细 - 更少的处理 - 更有可能将JIT转换为高效..

    另外,无论如何,foreach()都会分配一个新的枚举器。 在GC是你的朋友,但如果你重复做同样的foreach,这将使更多的一次性的对象,而不是重用相同的委托- 但是 -这实在是一个边缘的情况下。 在典型的使用情况下,您将看到很少或没有差异。

    链接地址: http://www.djcxy.com/p/5143.html

    上一篇: foreach vs someList.ForEach(){}

    下一篇: Are dictionaries ordered in Python 3.6+?