93

我想知道 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>它总是按其索引的顺序进行迭代。但我仍然希望看到明确说明这一点的文档,类似于List.

4

6 回答 6

107

基本上它取决于IEnumerator实现 - 但对于 aList<T>它总是按照列表的自然顺序排列,即与索引器相同的顺序:list[0],list[1]list[2]

我不相信它有明确的记录——至少,我还没有找到这样的文档——但我认为你可以把它当作保证。对该排序的任何更改都会毫无意义地破坏各种代码。事实上,我会惊讶地看到任何IList<T>违反这一点的实现。诚然,很高兴看到它专门记录在案......

于 2009-11-24T14:03:17.307 回答
28

在Enumerator 的Microsoft Reference Source 页面上List<T>明确指出迭代是从 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();
}

希望它仍然与某人有关

于 2019-08-16T10:27:54.523 回答
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.
于 2009-11-24T14:10:07.777 回答
4

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

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

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

这解释了Enumerator如何用于泛型 List。起初,当前元素是未定义的,并使用 MoveNext 来获取下一项。

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

于 2009-11-24T14:03:58.973 回答
2

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

使用 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
于 2012-09-18T16:58:51.040 回答
1

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

如果您的程序依赖于排序,您可能希望在遍历列表之前对其进行排序。

线性搜索有点傻——但如果你需要某种方式的订单,你最好的选择是按该顺序制作项目。

于 2009-11-24T14:03:47.960 回答