C# 字典的枚举数是否为<;TKey,TValue>;按键值对的添加顺序返回键值对?

C# 字典的枚举数是否为<;TKey,TValue>;按键值对的添加顺序返回键值对?,c#,.net,collections,C#,.net,Collections,我理解词典不是有序的集合,不应该依赖于词典中插入和检索的顺序 然而,我注意到: 向字典中添加了20个键值对 通过执行foreach(KeyValuePair…)检索它们 检索顺序与添加顺序相同。 测试了大约16个键值对 这是设计的吗?来自: 出于枚举目的,字典中的每个项都被视为表示值及其键的KeyValuePair)结构返回项目的顺序未定义 [强调添加]我不这么认为,字典不允许对其中的项目进行内部排序。 如果您还需要保持顺序,请在使用字典的同时使用其他数据结构(数组或列表)。这是巧合,尽管可

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

然而,我注意到:

  • 向字典中添加了20个键值对
  • 通过执行foreach(KeyValuePair…)检索它们
检索顺序与添加顺序相同。 测试了大约16个键值对

这是设计的吗?

来自:

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


[强调添加]

我不这么认为,字典不允许对其中的项目进行内部排序。
如果您还需要保持顺序,请在使用字典的同时使用其他数据结构(数组或列表)。

这是巧合,尽管可以预见。你绝对不应该依赖它。通常情况下,这种情况会发生在简单的情况下,但是如果您开始删除元素并用具有相同哈希代码的任何内容替换它们,或者只是将它们放在同一个存储桶中,那么该元素将占据原始元素的位置,尽管添加的时间比其他元素晚

复制这一点相对比较麻烦,但我在不久前成功地做到了:

使用系统;
使用System.Collections.Generic;
课堂测试
{
静态void Main(字符串[]参数)
{
var dict=新字典();
dict.Add(0,0);
添加(1,1)条;
添加(2,2);
dict.Remove(0);
添加(10,10);
foreach(dict中的var条目)
{
控制台写入线(entry.Key);
}
}
}
结果显示为10,1,2而不是1,2,10


请注意,即使当前的行为看起来总是按照插入顺序生成元素(如果不执行任何删除),也不能保证将来的实现也会这样做。。。因此,即使在您知道不会删除任何内容的受限情况下,也请不要依赖于此。

我相信,如果所有键散列到相同的值,枚举
字典将返回与插入键相同的顺序。这是因为
Dictionary
实现使用key对象的哈希代码将键/值对插入到bucket中,并且值(通常)按照插入顺序存储在bucket中。如果您在用户定义的对象中始终看到这种行为,那么可能您没有(正确地)重写
GetHashCode()
方法?

设计上,该方法不是一种有序结构,因为它主要用于基于键的访问


如果您需要按特定顺序检索项,则应查看,它将使用a对中的键进行排序。

如果您希望按固定顺序遍历字典,则可以尝试这是设计的吗?它可能不在最初的.Net Framework 2.0中,但现在有一个隐式约定,它们将按照添加的顺序进行排序,因为更改这一点将破坏太多依赖于原始泛型词典行为的代码。与Go语言相比,他们的地图故意返回随机顺序,以防止地图用户依赖任何顺序[1]

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


[1] “自从Go 1.0发布以来,运行时已经随机映射了迭代顺序。”,。

相关问题:我想你可能误解了这个问题。他在问他看到结果的有序性是否是出于设计。谢谢Jon,我的意思是字典不是有序结构这一事实是出于设计。我最好澄清一下我的答案(在火车上的iPhone上回答可能会很棘手:)@Russ:是的-我意识到你在说什么,但它没有回答被问到的“是否是设计的”问题:)+1-这个例子帮助我重现了我场景中的行为,这样我就可以“看到”它的实际行动,帮助我避免潜在的陷阱。我问了一个有点相关的问题,其中有一段代码,在.NET Core 3.1中使用
字符串作为键时,显示了
ImmutableDictionary
枚举的不确定性。这提供了一个示例,其中当前的行为不会按插入顺序生成元素(尽管是针对
ImmutableDictionary
)。请与我分享一些文档或文章,我可以在其中阅读有关保留插入顺序的默认合同的更多信息吗?我什么也找不到。没有合同说它能维持秩序。事实上,根据Jon Skeet的回答,当存在删除时,排序会发生故障。我只是认为目前的行为不太可能改变。
using System;
using System.Collections.Generic;

class Test
{
    static void Main(string[] args)
    {
        var dict = new Dictionary<int, int>();        
        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);
        }
    }
}