每个循环的C#以什么顺序遍历List <T>?


82

我想知道C#中的foreach循环遍历System.Collections.Generic.List<T>对象的顺序。

我发现关于同一主题的另一个问题,但是我认为它不能使我满意。

有人指出没有顺序被定义。但是正如其他人所述,它遍历数组的顺序是固定的(从0到Length-1)。8.8.4 foreach语句

也有人说,对于带有顺序的任何标准类(例如List<T>)也是如此。我找不到任何文档来进行备份。因此,就我所知,它现在可能会像现在那样工作,但是也许在下一个.NET版本中,它会有所不同(即使可能不太可能)。

我也看了List(t).Enumerator运气不好的文档。

另一个相关问题指出,对于Java,它在文档中特别提到:

List.iterator()以正确的顺序返回此列表中元素的迭代器。”

我正在C#文档中寻找类似的内容。

提前致谢。

编辑:谢谢您为我提供的所有答案(令人惊奇的是我得到这么多回复的速度如此之快)。从所有答案中我了解到的是,List<T>它始终会按其索引顺序进行迭代。但是我仍然希望看到一个清晰的文档说明这一点,类似于上的Java文档List

Answers:


13

Microsoft参考源页面上List<T>Enumerator上,明确声明了迭代是从0到Length-1完成的:

internal Enumerator(List<T> list) {
    this.list = list;
    index = 0;
    version = list._version;
    current = default(T);
}

public bool MoveNext() {

    List<T> localList = list;

    if (version == localList._version && ((uint)index < (uint)localList._size)) 
    {                                                     
        current = localList._items[index];                    
        index++;
        return true;
    }
    return MoveNextRare();
}

希望它对某人仍然有意义


102

基本上它是到IEnumerator执行-但对于List<T>它会在列表中的自然顺序,即相同的顺序与索引总是:list[0]list[1]list[2]等。

我不认为它有明确的文档-至少,我还没有找到这样的文档-但我认为您可以将其视为有保证的文档。对该顺序的任何更改都将毫无意义地破坏所有类型的代码。实际上,我很惊讶地看到任何实现IList<T>都违反了这一点。诚然,很高兴看到它有专门记录...


我实际上只是在5秒钟前检查了答案,并且打算发布类似的内容。你太快了!
Michael G

多谢您的回覆。有一些文件可以保证这一点吗?
Matthijs Wessels,2009年

1
@Michael G:虽然我不会依赖MSDN示例代码作为文档。我已经看到太多令人震惊的错误。
乔恩·斯基特

1
有人可以提供有关阵列的相同答案吗?
yazanpro

12
@yazanpro:foreach肯定会按数组顺序进行迭代。
乔恩·斯基特

8

在您的链接中,可接受的答案在C#语言规范版本3.0,第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
是的,但这是一个数组。它是否也自动适用于List <T>类?
Matthijs Wessels,

2
List <T>将数组用于其后备存储。是的
乔尔·穆勒

9
但这是一个实现细节。List <T>不需要使用数组作为其后备存储。
埃里克·利珀特

3
我想指出List <T>的文档(在示例代码中):“ List <(Of <(T>)>)类是ArrayList类的泛型等效项。它实现了IList <(Of <(T>)>)通用接口,使用其大小根据需要动态增加的数组。” (强调我的意思)
RCIX

嗯,我猜它总是使用数组。但这仍然意味着它不能返回反向枚举器吗?
Matthijs Wessels,2009年

4

该顺序由迭代器定义,该迭代器用于使用foreach循环遍历数据集合。

如果您使用的是可索引的标准集合(例如List),则它将遍历该集合,从索引0开始并向上移动。

如果需要控制排序,则可以通过实现自己的IEnumerable来控制如何处理集合的迭代,也可以在执行foreach循环之前按照所需的方式对列表进行排序。

这说明了枚举器如何用于通用列表。首先,当前元素是不确定的,并使用MoveNext转到下一项。

如果您阅读MoveNext,则表示它将从集合的第一个元素开始,然后从那里移动到下一个元素,直到到达集合的末尾。


感谢您的答复和补充(每个人的回答都这么快,我几乎无法跟上)。我也读过。也许我只是一个<word来指定一个想要太精确的人>,但是我觉得当他们说“第一个元素”时,它们表示将要迭代的第一个元素,而不是第一个要重复的元素按照迭代类的顺序。
Matthijs Wessels,2009年

好吧,如果您确定它能够按预期的方式运行非常重要,那么最好的方法就是按照我说的做,自己实现IEnumerable。
布伦丹·恩里克

1

列表似乎按后备存储中的顺序返回项目-因此,如果以这种方式将它们添加到列表中,则会以这种方式返回。

如果您的程序取决于顺序,则可能需要在遍历列表之前对其进行排序。

对于线性搜索而言,这有点愚蠢-但是,如果您需要某种方式的订购,则最好的选择就是按照该顺序订购商品。


1

我只需要做一些类似于快速破解代码的操作,尽管它对我尝试执行的操作不起作用,但确实为我重新排序了列表。

使用LINQ更改订单

         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

我不认为这与问题有何关系。您的代码甚至没有使用List。我认为您误解了“列表”的含义。
Matthijs Wessels,2012年

另外,为什么你复制的内容ColumnsgridColumns第一?我认为您也可以这样做:DataGridViewColumn[] gridColumns = dataGridView1.Columns.OrderByDescending(n => n.DisplayIndex).ToArray();
Matthijs Wessels

@MatthijsWessels如果愿意,使用List可以很容易地对其进行更改。
奥斯汀·亨利

@AustinHenley您可以在IOrderedEnumerable上进行foreach,但这不是问题所在。您也可以对ToList而不是ToArray进行操作,但是您又有了一个List,并且仍然无法回答foreach是否将以指定的顺序遍历项目的问题。
Matthijs Wessels
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.