当前位置:  开发笔记 > 编程语言 > 正文

foreach vs someList.ForEach(){}

如何解决《foreachvssomeList.ForEach(){}》经验,为你挑选了5个好方法。

显然有很多方法可以迭代集合.好奇,如果有任何差异,或为什么你使用一种方式而不是另一种方式.

第一种:

List someList = 
foreach(string s in someList) {
   
}

另一种方式:

List someList = 
someList.ForEach(delegate(string s) {
    
});

我认为,除了我上面使用的匿名代表之外,我还有一个你可以指定的可重用代理......



1> 小智..:

两者之间有一个重要且有用的区别.

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

通常,如果您要从列表中删除多个项目,则需要将确定要从实际删除中删除的项目分开.它不会保持您的代码紧凑,但它保证您不会错过任何项目.


即使这样,你也应该使用someList.RemoveAll(x => x.RemoveMe)
如果使用for循环向后迭代****,则可以删除没有任何索引移位问题的项目.
你可能已经意识到了这一点,但人们应该注意以这种方式移除物品; 如果你删除项目N然后迭代将跳过项目(N + 1),你将不会在你的委托中看到它或有机会删除它,就像你在你自己的for循环中做到这一点.
有了Linq,一切都可以做得更好.我只是展示了一个在foreach中修改集合的例子......
RemoveAll()是List 上的方法.

2> Anthony..:

我们在这里度过了一段代码(在VS2005和C#2.0)在先前工程师走出自己使用的方式list.ForEach( delegate(item) { foo;});,而不是foreach(item in list) {foo; };对所有他们编写的代码.例如,用于从dataReader读取行的代码块.

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

缺点list.ForEach()是:

它在C#2.0中更加冗长.但是,在C#3之后,您可以使用" =>"语法来制作一些非常简洁的表达式.

它不太熟悉.必须维护此代码的人会想知道为什么你这样做.我花了一段时间才决定没有任何理由,除了可能让作家看起来很聪明(其余代码的质量破坏了这一点).它的可读性也较低,})代理代码块末尾的" ".

另请参阅Bill Wagner的书"有效的C#:50改进C#的具体方法",其中他谈到为什么foreach比其他循环更喜欢for或while循环 - 主要的一点是你让编译器决定构建的最佳方法循环.如果未来版本的编译器设法使用更快的技术,那么您将通过使用foreach和rebuilding而不是更改代码来免费获得此技术.

一个foreach(item in list)结构允许你使用break或者continue如果你需要退出迭代或循环.但是你不能改变foreach循环中的列表.

我很惊讶地看到它list.ForEach稍快一些.但这可能不是一直使用它的正当理由,那将是不成熟的优化.如果您的应用程序使用的数据库或Web服务,而不是循环控制,几乎总是会在时间的推移.你有没有对它进行基准测试for?将list.ForEach可能会更快,由于使用内部和for没有包装循环甚至会更快.

我不同意该list.ForEach(delegate)版本在任何重要方面都"更具功能性".它确实将函数传递给函数,但结果或程序组织没有太大差异.

我不认为foreach(item in list)"确切地说你想要它做什么" - 一个for(int 1 = 0; i < count; i++)循环就是这样,一个foreach循环将控制选择留给了编译器.

我的感觉是,在一个新项目中,foreach(item in list)为了坚持常用和可读性而使用大多数循环,并且list.Foreach()只能用于短块,当你可以使用C#3" =>"操作符更优雅或更紧凑地执行操作时.在这种情况下,可能已经有一个更具体的LINQ扩展方法ForEach().看看Where(),Select(),Any(),All(),Max()或许多其他LINQ方法中的一种尚不你从循环想要的东西.


不知道为什么它是-1,因为我发现它是一个很好的答案.

3> plinth..:

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

public void ForEach(Action 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更加严格 - 处理更少 - 更有可能J​​IT变成高效的东西.

另外,无论如何,foreach()都会分配一个新的枚举器.GC是你的朋友,但如果你反复做同样的事情,这会产生更多的一次性物品,而不是重复使用同一个代表 - 但是 - 这实际上是一个边缘情况.在典型的使用中,您将看到很少或没有区别.



4> Daniel Earwi..:

我知道两件让他们与众不同的晦涩难懂的事物.去吧!

首先,存在为列表中的每个项目制作委托的经典错误.如果使用foreach关键字,则所有代理最终都可以引用列表的最后一项:

    // A list of actions to execute later
    List actions = new List();

    // Numbers 0 to 9
    List 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();

List.ForEach方法没有此问题.迭代的当前项通过值作为参数传递给外部lambda,然后内部lambda在其自己的闭包中正确捕获该参数.问题解决了.

(遗憾的是我相信ForEach是List的成员,而不是扩展方法,虽然很容易自己定义它,所以你可以在任何可枚举的类型上使用它.)

其次,ForEach方法方法有局限性.如果使用yield return实现IEnumerable,则无法在lambda中执行yield return.因此,通过此方法无法循环遍历集合中的项目以产生返回事物.您必须使用foreach关键字并通过手动在循环内复制当前循环值来解决闭包问题.

更多这里


你在`foreach`中提到的问题在C#5中是"固定的".http://stackoverflow.com/questions/8898925/is-there-a-reason-for-cs-reuse-of-the-variable-in- A-的foreach

5> Joachim Kers..:

我想这个someList.ForEach()调用可以很容易地并行化,而法线foreach并不容易并行.您可以轻松地在不同的核心上运行几个不同的代理,这对于普通代码来说并不容易foreach.
只需2美分


我认为他的意思是运行时引擎可以自动并行化它.否则,foreach和.ForEach都可以使用每个操作委托中池中的线程手动并行化
推荐阅读
mobiledu2402851173
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有