16

假设我有一个给定的集合。在不以任何方式更改集合的情况下,我使用 foreach 循环遍历其内容两次。除了宇宙射线之外,是否绝对保证两个循环中的顺序是一致的?

或者,给定HashSet<string>具有多个元素的 a,可能导致以下注释行的输出不相等:

{
    var mySet = new HashSet<string>();
    // Some code which populates the HashSet<string>

    // Output1
    printContents(mySet);

    // Output2
    printContents(mySet);
}

public void printContents(HashSet<string> set) {
    foreach(var element in set) {
         Console.WriteLine(element);
    }
}

如果我能得到一个一般性的答案来解释导致实现不符合上述标准的原因,那将会很有帮助。不过,具体来说,我对Dictionary,List和数组很感兴趣。

4

4 回答 4

15

数组枚举保证顺序。

ListList<T>有望提供稳定的顺序(因为它们有望实现顺序索引的元素)。

Dictionary、HashSet 都明确不保证顺序。2 个一个接一个地迭代项目的调用不太可能以不同的顺序返回项目,但没有保证或期望。人们不应该期望任何特定的顺序。

Dictionary/HashSet 的排序版本按排序顺序返回项目。

其他 IEnumerable 对象可以自由地做任何他们想做的事情。通常以符合用户期望的方式实现迭代器。即具有隐式顺序的事物的枚举应该是稳定的,如果提供了明确的顺序 - 预期是稳定的。对未指定顺序的数据库的查询应该以半随机顺序返回项目。

检查此问题的链接:C# 中的 foreach 循环是否保证评估顺序?

于 2012-07-27T02:29:38.487 回答
5

实现的一切都IEnumerable<T>以自己的方式进行。没有一般保证任何给定的集合必须确保稳定性。

如果您专门指的是Collection<T>http://msdn.microsoft.com/en-us/library/ms132397.aspx),我在其 MSDN 参考中没有看到任何关于排序一致的具体保证。

它可能会保持一致吗?是的。有书面保证吗?不是我能找到的。

于 2012-07-27T01:43:27.023 回答
3

对于许多 C# 集合,有该集合的排序版本。例如, aHashSet对 aSortedSet就像 aDictionary对 a一样SortedDictionary。如果您正在使用顺序不重要的东西,Dictionary那么您不能假设循环顺序每次都会以相同的方式运行。

于 2012-07-27T01:57:25.297 回答
0

根据您的示例HashSet<T>,我们现在有要检查的源代码:HashSet:Enumerator

事实上,Slot[] set.m_slots数组是迭代的。数组对象只在方法TrimExcess, Initialize(这两个方法都只在构造函数中调用)OnDeserialization、 和SetCapacity(只被AddIfNotPresentand调用AddOrGetLocation)中改变。

的值m_slots仅在更改HashSet( Clear, Remove, AddIfNotPresent, IntersectWith, SymmetricExceptWith) 元素的方法中更改。

所以是的,如果没有任何东西触及集合,它会以相同的顺序枚举。

Dictionary:Enumerator的工作方式完全相同,迭代Entry[] entries仅在调用此类非只读方法时才会更改。

于 2016-09-05T18:22:45.847 回答