2009-11-24 46 views
57

我想知道C#中的foreach循環通過System.Collections.Generic.List<T>對象循環的順序。每個循環的C#以什麼順序迭代列表<T>?

我發現another question關於同一主題,但我不覺得它回答我的問題,我的滿意。

有人說沒有定義訂單。但是,正如其他人所說,它遍歷數組的順序是固定的(從0到Length-1)。 8.8.4 The foreach statement

也有人說,對於任何具有訂單的標準類別(例如List<T>)也是如此。我找不到任何文件來支持它。所以我知道現在可能會這樣,但是在下一個.NET版本中它可能會有所不同(即使它不太可能)。

我也看過List(t).Enumerator文檔沒有運氣。

Another related question指出,對於Java,它是專門的文件中提到:

List.iterator()返回在正確的順序在此列表中 元素的迭代器」

我要找類似於C#文檔中的內容。

提前致謝。

編輯:謝謝你所有的答案(驚人的速度有多快我收到了這麼多的回覆)。我從所有答案中瞭解到,List<T>總是按其索引順序進行迭代。但我仍然希望看到文件明確說明這一點,類似於Java documentation on List

回答

72

基本上它是一個到IEnumerator實現 - 但對於一個List<T>它總是在列表中的自然順序,即相同的順序與索引:list[0]list[1]list[2]

我不我相信它有明確的記錄 - 至少,我沒有找到這樣的文檔 - 但我認爲你可以把它看作是有保證的。任何對該順序的更改都會毫無意義地破壞所有類型的代碼。事實上,我很驚訝地發現IList<T>的任何實施都違反了這個規定。無可否認,它會很高興地看到它具體記錄...

+0

。你太快了! –

+0

感謝您的回覆。是否有一些文件保證這一點? –

+0

對於IList你當然更好的遵循這個標準的實現。對於某些集合,集合中的項目不一定有明顯的順序,因此它可以以不同的方式實現。 –

1

列表似乎返回的項目,他們在後備存儲的順序 - 所以如果他們被添加到列表中,他們將被返回辦法。

如果您的程序依賴於排序,您可能需要在遍歷列表之前對其進行排序。

線性搜索有點愚蠢 - 但如果您需要某種方式的訂單,最好的選擇是按照該順序製作這些項目。

3

該順序由用於使用foreach循環遍歷數據集合的迭代器定義。

如果您使用的是可編制索引的標準集合(例如List),則它將遍歷從索引0開始並向上移動的集合。

如果您需要控制順序,您可以控制集合迭代的處理方式如何處理implementing your own IEnumerable,或者您可以在執行foreach循環之前以您想要的方式對列表進行排序。

這解釋了Enumerator如何適用於通用列表。起初,當前元素未定義,並使用MoveNext轉到下一個項目。

如果您讀取的是MoveNext,則表示它將從集合的第一個元素開始,然後移動到下一個元素,直到到達集合的末尾。

+0

感謝您的回覆和補充(每個人都回答如此之快,我幾乎無法跟上)。我也讀過。也許我只是一個<單詞來指定一個想要過於精確的人>,但我覺得當他們說「第一個元素」時,他們意味着要迭代的第一個元素,而不是第一個元素到迭代類的順序。 –

+0

好吧,如果確定它符合您的期望,那麼最好的方法就是按照我所說的來實現IEnumerable。 –

8

在你的鏈接,在C# Language Specification Version 3.0, page 240接受的答案狀態:

在其中的foreach橫穿陣列的 的元素,是 如下順序:對於一維數組 元素以增加穿過 索引順序,從索引0開始和 索引Length結束 - 1.對於 多維數組,元件 遍歷使得 最右邊的維的索引增加 第一,然後在左邊的下一個左邊維度 等等。下面 示例打印出在 二維陣列的每個值,在元件 順序:

using System; 
class Test 
{ 
    static void Main() { 
     double[,] values = { 
      {1.2, 2.3, 3.4, 4.5}, 
      {5.6, 6.7, 7.8, 8.9} 
     }; 
     foreach (double elementValue in values) 
      Console.Write("{0} ", elementValue); 
     Console.WriteLine(); 
    } 
} 

產生的輸出如下所示: 1.2 2.3 3.4 4.5 5.6 6.7 7.8 8.9在該示例

int[] numbers = { 1, 3, 5, 7, 9 }; 
foreach (var n in numbers) Console.WriteLine(n); 
the type of n is inferred to be int, the element type of numbers. 
+2

是的,但這是一個數組。它是否也會自動保持列表類? –

+2

列表使用數組作爲其後備存儲。所以是的。 –

+8

但這是一個實現細節。列表不是必需的*以將數組用作其後備存儲。 –

1

我只是不得不做一些類似於快速破解代碼的東西,儘管它沒有用於我正在嘗試做的事情,所以對我重新排列列表。

使用LINQ改變我真的只是檢查的回答5個小時前,正要張貼類似的東西的順序

  DataGridViewColumn[] gridColumns = new DataGridViewColumn[dataGridView1.Columns.Count]; 
     dataGridView1.Columns.CopyTo(gridColumns, 0); //This created a list of columns 

     gridColumns = (from n in gridColumns 
         orderby n.DisplayIndex descending 
         select n).ToArray(); //This then changed the order based on the displayindex 
+0

我不明白這與問題有關。你的代碼甚至不使用'List'。我想你誤解了我的意思是「名單」。 –

+0

另外,你爲什麼首先將'Columns'的內容複製到'gridColumns'?我認爲你也可以這樣做:'DataGridViewColumn [] gridColumns = dataGridView1.Columns.OrderByDescending(n => n.DisplayIndex).ToArray();' –

+0

@MatthijsWessels這不難改變,使用List,如果你想。 –