字典的枚举器是否按照添加的顺序返回键值对?

我理解字典不是有序集合,不应该依赖于字典中插入和检索的顺序。

但是,这是我注意到的:

  • 为Dictionary添加了20个键值对
  • 通过做foreach(KeyValuePair …)检索它们

检索顺序与添加顺序相同。 测试了大约16个键值对。

这是设计的吗?

虽然可以预见,但这只是巧合。 你绝对不应该依赖它。 通常它在简单的情况下发生,但是如果你开始删除元素并用任何具有相同哈希码的东西替换它们或只是进入同一个桶,那么该元素将采用原始位置,尽管比其他元素更晚添加。

重现这一点是相对繁琐的,但我不久前设法做了另一个问题 :

using System; using System.Collections.Generic; class Test { static void Main(string[] args) { var dict = new Dictionary(); dict.Add(0, 0); dict.Add(1, 1); dict.Add(2, 2); dict.Remove(0); dict.Add(10, 10); foreach (var entry in dict) { Console.WriteLine(entry.Key); } } } 

结果显示10,1,2而不是1,2,10。

请注意,即使看起来当前行为总是会在插入顺序中产生元素,如果你不执行任何删除,也不能保证未来的实现会做同样的事情……所以即使在你知道你赢了的限制情况下也是如此不删除任何东西,请不要依赖于此。

来自MSDN :

出于枚举的目的,字典中的每个项都被视为表示值及其键的KeyValuePair<(Of <(TKey, TValue>)>)结构。 返回项的顺序未定义

[强调补充]

如果要以固定顺序迭代字典,可以尝试使用OrderedDictionary

根据设计, Dictionary不是有序结构,因为它主要用于基于密钥的访问。

如果您需要按特定顺序检索项目,则应该查看Sorted Dictionary ,它将使用Comparer来对Sorted Dictionary的键进行Sorted Dictionary

我不这么认为,字典没有授予其内部项目的内部排序。 如果您还需要保留订单,请使用其他数据结构(数组或列表)以及字典。

我相信如果所有键都散列到相同的值 Dictionary枚举Dictionary将按照它们插入的相同顺序返回键。 这是因为Dictionary实现使用密钥对象的哈希码将键/值对插入到桶中,并且值(通常)按插入顺序存储在桶中。 如果您始终使用用户定义的对象看到此行为,那么您可能还没有(正确地)覆盖GetHashCode()方法?

这是设计的吗? 它可能不是最初的.Net Framework 2.0,但是现在有一个隐式契约,它们将按照添加的顺序排序,因为要改变它会破坏那么多依赖于原始通用行为的代码字典。 与Go语言相比,他们的地图故意返回一个随机排序,以防止地图用户依赖任何排序[1]。

框架编写者对Dictionary 所做的任何改进或更改都必须保留该隐式契约。

[1]“自Go 1.0发布以来,运行时已经随机化了地图迭代顺序。”, https://blog.golang.org/go-maps-in-action 。