2008-09-04 49 views
12

我被告知在下面的代碼塊之間存在性能差異。C#中IEnumerable類的foreach和for循環之間的區別

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

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

其中

List<Entity> entityList; 

我也不指望CLR但我可以告訴他們應該歸結爲基本相同的代碼。有沒有人有這樣或那樣的具體(嘿,我會採取包裝污垢)證據?

回答

8

foreach創建一個枚舉器的實例(從GetEnumerator返回),並且該枚舉器在整個foreach循環過程中也保持狀態。然後它重複調用枚舉數上的Next()對象,併爲其返回的每個對象運行代碼。

它們不會以任何方式歸結爲相同的代碼,真的,如果您編寫自己的枚舉器,您會看到它。

9

Here是一篇很好的文章,顯示了兩個循環之間的IL差異。

Foreach在技術上比較慢,但使用起來更容易,也更易於閱讀。除非性能至關重要,否則我更喜歡for循環的foreach循環。

0

我認爲一種可能的情況,其中可能得到的性能增益是如果可枚舉類型的大小和循環條件是一個常數;例如:

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

//... 

for (int i = 0; i

在這種情況下,根據循環體的複雜性,編譯器可能能夠用內聯調用替換循環。我不知道.NET編譯器是否執行此操作,並且如果可枚舉類型的大小是動態的,則它的實用程序有限。

其中foreach可能表現更好的一種情況是數據結構像鏈接列表,其中隨機訪問意味着遍歷列表;由foreach使用的枚舉器可能會一次迭代一個項目,使得每個訪問O(1)和完整循環O(n),但調用索引器意味着從頭部開始並在右側索引中找到該項目; O(N)每個循環爲O(n^2)。

就我個人而言,我通常不用擔心,並且隨時需要使用foreach我需要所有物品並且不關心物品的索引。如果我沒有使用所有的項目,或者我真的需要知道索引,我使用。我唯一能看到它是一個大問題的是像鏈表這樣的結構。

6

在foreach樣品大致相當於此代碼:

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

這裏有兩個成本,一個普通的for循環不必支付:

  1. 通過分配枚舉器對象的成本entityList.GetEnumerator()。
  2. 列表中每個元素的兩個虛方法調用(MoveNext和Current)的代價。
1

就分配而言,最好是看看this blogpost。它完全顯示了在什麼情況下枚舉器在堆上分配。

3

有一點在這裏錯過了: 一個List有一個Count屬性,它在內部跟蹤其中有多少個元素。

IEnumerable不。

如果您編程接口IEnumerable並使用計數擴展方法,它將枚舉只計算元素。

儘管由於在IEnumerable中沒有辦法引用項目索引。

所以,如果你想鎖定列表和數組,你可以獲得小的性能提升。

如果您希望flexability使用foreach並編程爲IEnumerable。 (允許使用linq和/或收益回報)。

0
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; 
} 
相關問題