C# 中 IEnumerable 类的 foreach 和 for 循环之间的区别

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/44220/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 09:54:19  来源:igfitidea点击:

Difference between foreach and for loops over an IEnumerable class in C#

提问by Craig

I have been told that there is a performance difference between the following code blocks.

有人告诉我,以下代码块之间存在性能差异。

foreach (Entity e in entityList)
{
 ....
}

and

for (int i=0; i<entityList.Count; i++)
{
   Entity e = (Entity)entityList[i];
   ...
}

where

在哪里

List<Entity> entityList;

I am no CLR expect but from what I can tell they should boil down to basically the same code. Does anybody have concrete (heck, I'd take packed dirt) evidence one way or the other?

我不是 CLR 所期望的,但据我所知,它们应该归结为基本相同的代码。有没有人以一种或另一种方式有混凝土(见鬼,我会带上泥土)证据?

采纳答案by Daniel Jennings

foreach creates an instance of an enumerator (returned from GetEnumerator) and that enumerator also keeps state throughout the course of the foreach loop. It then repeatedly calls for the Next() object on the enumerator and runs your code for each object it returns.

foreach 创建一个枚举器实例(从 GetEnumerator 返回),并且该枚举器还在整个 foreach 循环过程中保持状态。然后它重复调用枚举器上的 Next() 对象,并为它返回的每个对象运行您的代码。

They don't boil down to the same code in any way, really, which you'd see if you wrote your own enumerator.

它们不会以任何方式归结为相同的代码,实际上,如果您编写自己的枚举器,您就会看到这些代码。

回答by David Basarab

Hereis a good article that shows the IL differences between the two loops.

是一篇很好的文章,展示了两个循环之间的 IL 差异。

Foreach is technically slower however much easier to use and easier to read. Unless performance is critical I prefer the foreach loop over the for loop.

Foreach 在技术上较慢,但更易于使用和阅读。除非性能至关重要,否则我更喜欢 foreach 循环而不是 for 循环。

回答by OwenP

I think one possible situation where you mightget a performance gain is if the enumerable type's size and the loop condition is a constant; for example:

我认为您可能会获得性能提升的一种可能情况是可枚举类型的大小和循环条件是否为常量;例如:

const int ArraySize = 10;
int[] values = new int[ArraySize];

//...

for (int i = 0; i 

In this case, depending on the complexity of the loop body, the compiler might be able to replace the loop with inline calls. I have no idea if the .NET compiler does this, and it's of limited utility if the size of the enumerable type is dynamic.

One situation where foreachmight perform better is with data structures like a linked list where random access means traversing the list; the enumerator used by foreachwill probably iterate one item at a time, making each access O(1) and the full loop O(n), but calling the indexer means starting at the head and finding the item at the right index; O(N) each loop for O(n^2).

In this case, depending on the complexity of the loop body, the compiler might be able to replace the loop with inline calls. I have no idea if the .NET compiler does this, and it's of limited utility if the size of the enumerable type is dynamic.

One situation where foreachmight perform better is with data structures like a linked list where random access means traversing the list; the enumerator used by foreachwill probably iterate one item at a time, making each access O(1) and the full loop O(n), but calling the indexer means starting at the head and finding the item at the right index; O(N) each loop for O(n^2).

Personally I don't usually worry about it and use foreachany time I need all items and don't care about the index of the item. If I'm not working with all of the items or I really need to know the index, I use for. The only time I could see it being a big concern is with structures like linked lists.

Personally I don't usually worry about it and use foreachany time I need all items and don't care about the index of the item. If I'm not working with all of the items or I really need to know the index, I use for. 我唯一一次看到它是一个大问题,那就是像链表这样的结构。

回答by OwenP

The foreach sample roughly corresponds to this code:

foreach示例大致对应如下代码:

using(IEnumerator<Entity> e = entityList.GetEnumerator()) {
    while(e.MoveNext()) {
        Entity entity = e.Current;
        ...
    }
}

There are two costs here that a regular for loop does not have to pay:

这里有两个常规 for 循环不必支付的成本:

  1. The cost of allocating the enumerator object by entityList.GetEnumerator().
  2. The cost of two virtual methods calls (MoveNext and Current) for each element of the list.
  1. 通过 entityList.GetEnumerator() 分配枚举器对象的成本。
  2. 为列表中的每个元素调用两个虚拟方法(MoveNext 和 Current)的成本。

回答by Patrick

In terms of allocations, it'd be better to look at this blogpost. It shows in exactly in what circumstances an enumerator is allocated on the heap.

在分配方面,最好看一下这篇博文。它准确地显示了在什么情况下在堆上分配了枚举数。

回答by Brian Leahy

One point missed here: A List has a Count property, it internally keeps track of how many elements are in it.

这里遗漏了一点:List 有一个 Count 属性,它在内部跟踪其中有多少元素。

An IEnumerable DOES NOT.

IEnumerable 没有。

If you program to the interface IEnumerable and use the count extention method it will enumerate just to count the elements.

如果您编程到接口 IEnumerable 并使用计数扩展方法,它将枚举只是为了计算元素。

A moot point though since in the IEnumerable you cannot refer to items by index.

尽管在 IEnumerable 中您不能按索引引用项目,但这是一个有争议的问题。

So if you want to lock in to Lists and Arrays you can get small performance increases.

因此,如果您想锁定列表和数组,您可以获得小的性能提升。

If you want flexability use foreach and program to IEnumerable. (allowing the use of linq and/or yield return).

如果你想灵活使用 foreach 并编程到 IEnumerable。(允许使用 linq 和/或收益回报)。

回答by kavitha Reddy

For Loop
for loop is used to perform the opreration n times
for(int i=0;i<n;i++)
{
l=i;
}
foreach loop

int[] i={1,2,3,4,5,6}
foreach loop is used to perform each operation value/object in IEnumarable 
foreach(var k in i)
{
l=k;
}