简体   繁体   English

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

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

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. 我不是CLR期望的,但是据我所知,它们应该归结为基本相同的代码。 Does anybody have concrete (heck, I'd take packed dirt) evidence one way or the other? 是否有人以一种或另一种方式证明混凝土(哎呀,我要塞满灰尘)?

foreach creates an instance of an enumerator (returned from GetEnumerator) and that enumerator also keeps state throughout the course of the foreach loop. foreach创建一个枚举器的实例(从GetEnumerator返回),并且该枚举器还在foreach循环的整个过程中保持状态。 It then repeatedly calls for the Next() object on the enumerator and runs your code for each object it returns. 然后,它反复在枚举器上调用Next()对象,并为返回的每个对象运行代码。

They don't boil down to the same code in any way, really, which you'd see if you wrote your own enumerator. 实际上,它们不会以任何方式简化为相同的代码,如果您编写了自己的枚举器,您会看到它们。

Here is 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. 从技术上讲,Foreach速度较慢,但​​是更易于使用和阅读。 Unless performance is critical I prefer the foreach loop over the for loop. 除非性能至关重要,否则我更喜欢foreach循环而不是for循环。

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(). 由entityList.GetEnumerator()分配枚举数对象的成本。
  2. The cost of two virtual methods calls (MoveNext and Current) for each element of the list. 列表中每个元素调用两个虚拟方法(MoveNext和Current)的成本。

One point missed here: A List has a Count property, it internally keeps track of how many elements are in it. 这里遗漏了一点:列表具有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接口进行编程并使用count扩展方法,它将仅枚举来对元素进行计数。

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. 如果要灵活性,请使用foreach并将其编程为IEnumerable。 (allowing the use of linq and/or yield return). (允许使用linq和/或收益率回报)。

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. 它确切显示了在什么情况下在堆上分配了枚举数。

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

I think one possible situation where you might get 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 foreach might perform better is with data structures like a linked list where random access means traversing the list; the enumerator used by foreach will 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 foreach might perform better is with data structures like a linked list where random access means traversing the list; the enumerator used by foreach will 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 foreach any 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 Personally I don't usually worry about it and use foreach any 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 . Personally I don't usually worry about it and use foreach any 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. 我唯一看到的最大问题是链接列表之类的结构。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM