【问题标题】:In what order does a C# for each loop iterate over a List<T>?每个循环的 C# 以什么顺序迭代 List<T>?
【发布时间】:2010-12-19 21:37:37
【问题描述】:

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

我发现another question 是关于同一主题的,但我认为它对我的问题的回答并不令我满意。

有人说没有定义顺序。但正如其他人所说,它遍历数组的顺序是固定的(从 0 到 Length-1)。 8.8.4 The foreach statement

也有人说,任何有顺序的标准类也是如此(例如List&lt;T&gt;)。我找不到任何文档来支持它。所以据我所知,它现在可能会这样工作,但也许在下一个 .NET 版本中它会有所不同(即使它可能不太可能)。

我还查看了List(t).Enumerator 文档,但没有运气。

Another related question 表示对于 Java,文档中特别提到:

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

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

提前致谢。

编辑:感谢大家的所有回答(令人惊讶的是我收到这么多回复的速度有多快)。我从所有答案中了解到的是 List&lt;T&gt; 总是按照其索引的顺序进行迭代。但我仍然希望看到明确说明这一点的文档,类似于Java documentation on List。

【问题讨论】:

    标签: c# foreach operator-precedence


    【解决方案1】:

    基本上这取决于IEnumerator 的实现——但对于List&lt;T&gt;,它将始终按照列表的自然顺序排列,即与索引器的顺序相同:list[0]、list[1]、list[2]等等

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

    【讨论】:

    • 我确实在 5 秒前刚刚检查了一个答案,并且正要发布类似的内容。你太快了!
    • 感谢您的回复。是否有一些文件可以保证这一点?
    • @Michael G:虽然我不会依赖 MSDN 示例代码作为文档。我在其中看到了太多令人震惊的错误。
    • 任何人都可以就数组提供相同的答案吗?
    • @yazanpro: foreach 肯定会按数组顺序迭代。
    【解决方案2】:

    在Microsoft Reference Source page for List&lt;T&gt; 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();
    }
    

    希望它对某人仍然相关

    【讨论】:

    • 得到更好的答案永远不会太晚,而且没有比这个更好的答案了。
    【解决方案3】:

    在您的链接中,接受的答案状态为C# Language Specification Version 3.0, page 240:

    foreach 遍历的顺序 数组的元素,如 如下:对于一维数组 元素以递增方式遍历 索引顺序,从索引 0 开始, 以索引长度结尾 - 1。对于 多维数组,元素是 遍历使得 最右边的维度增加了 首先,然后是下一个左侧维度, 等等到左边。下列 示例打印出 a 中的每个值 二维数组,在元素中 顺序:

    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.
    

    【讨论】:

    • 是的,但这是针对数组的。它是否也自动适用于 List 类?
    • List 使用一个数组作为其后备存储。所以是的。
    • 但这是一个实现细节。 List 不是必需 使用数组作为其后备存储。
    • 我想指出 List 的文档(示例代码):“List)>) 类是 ArrayList 类的通用等价物. 它使用一个 array 实现 IList)>) 通用接口,其大小根据需要动态增加。 (强调我的)
    • 嗯,我猜它总是使用数组。但是,这是否意味着它不能返回反向枚举数?
    【解决方案4】:

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

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

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

    这解释了Enumerator 如何用于通用列表。起初,当前元素是未定义的,并使用 MoveNext 到达下一项。

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

    【讨论】:

    • 感谢您的回复和补充(大家回复的太快了,我都快跟不上了)。我也读过。也许我只是作为一个,但我觉得当他们说“第一个元素”时,他们的意思是要迭代的第一个元素,而不是第一个根据按照迭代类的顺序。
    • 好吧,如果您确定它按您期望的方式进行是那么重要,那么最好的方法就是按照我说的去做并自己实现 IEnumerable。
    【解决方案5】:

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

    使用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。我想你误解了我所说的“列表”的意思。
    • 还有,为什么要先把Columns的内容复制到gridColumns呢?我认为你也可以这样做:DataGridViewColumn[] gridColumns = dataGridView1.Columns.OrderByDescending(n =&gt; n.DisplayIndex).ToArray();
    • @MatthijsWessels 如果你愿意的话,改变它来使用 List 并不难。
    • @AustinHenley 您可以对 IOrderedEnumerable 进行 foreach,但这不是问题所在。您也可以对 ToList 而不是 ToArray 执行操作,但是您只需再次拥有一个 List,并且 foreach 是否会按指定顺序循环遍历项目的问题仍未得到解答。
    • 天啊。这正是我寻找此代码的目的。非常感谢!!!!
    【解决方案6】:

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

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

    线性搜索有点傻 - 但如果您需要某种方式的顺序,最好的办法是按该顺序制作项目。

    【讨论】:

      猜你喜欢
      • 2013-08-20
      • 1970-01-01
      • 2020-03-04
      • 2017-04-28
      • 2012-07-14
      • 2010-12-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多