假设我有一个给定的集合。在没有以任何方式更改集合的情况下,我使用foreach循环其内容两次。除了宇宙射线,什么不是,它绝对保证两个循环中的顺序是一致的吗?
或者,如果HashSet<string>
包含许多元素,那么可能导致以下注释行的输出不相等:
{
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
和数组感兴趣。
答案 0 :(得分:12)
数组枚举保证顺序。
预计 List
和List<T>
将提供稳定的订单(因为预期它们会实现顺序索引的元素)。
字典,HashSet明确不保证顺序。 2个一个接一个地迭代项目的调用不太可能以不同的顺序返回项目,但是没有保证或期望。不应该指望任何特定的订单。
Dictionary / HashSet的排序版本按排序顺序返回项目。
其他IEnumerable对象可以随意执行任何操作。通常,实现迭代器的方式与用户的期望相匹配。即如果提供了明确的顺序,那么具有隐式顺序的东西的枚举应该是稳定的 - 预期是稳定的。对未指定顺序的数据库的查询应该以半随机顺序返回项目。
请检查此问题以获取链接:Does the foreach loop in C# guarantee an order of evaluation?
答案 1 :(得分:4)
实现IEnumerable<T>
的所有内容都以自己的方式实现。没有一般保证任何给定的集合必须确保稳定性。
如果您具体提到Collection<T>
(http://msdn.microsoft.com/en-us/library/ms132397.aspx),我在其MSDN参考中没有看到任何特定保证,即排序是一致的。
它可能是一致的吗?是。有书面保证吗?不是我能找到的。
答案 2 :(得分:3)
对于许多C#集合,有已排序版本的集合。例如,HashSet
为SortedSet
,而Dictionary
为SortedDictionary
。如果您正在处理订单不重要的事情,例如Dictionary
,那么您不能假设循环次序每次都会以相同的方式运行。
答案 3 :(得分:0)
根据HashSet<T>
的示例,我们现在要检查源代码:HashSet:Enumerator
实际上,迭代了Slot[] set.m_slots
数组。
数组对象仅在方法TrimExcess
,Initialize
(两者都只在构造函数中调用),OnDeserialization
和SetCapacity
中更改(仅由{{{ 1}}和AddIfNotPresent
)。
AddOrGetLocation
的值只会在更改m_slots
(HashSet
,Clear
,Remove
,AddIfNotPresent
元素的方法中更改,IntersectWith
)。
所以是的,如果没有触及该集合,它将以相同的顺序枚举。
Dictionary:Enumerator以完全相同的方式工作,迭代只在调用此类非读取方法时才会更改的SymmetricExceptWith
。