.NET的字典中的元素是有序的吗?

6

假设我创建了一个这样的字典:

Dictionary<string, MyClass> dic = new Dictionary<string, MyClass>();

dic.add("z1", val1);
dic.add("abc9", val2);
dic.add("abc8", val3);
dic.add("ABC1", val4);

所以当我执行以下操作时:

foreach (KeyValuePair<string, MyClass> kvp in dic)
{
}

我能确保这些值被正确地检索出来:"z1", "abc9", "abc8", "ABC1"吗?
如果我先执行这个操作,结果是不是会是:"z1", "abc8", "ABC1"呢?请注意,保留的HTML标签不应该被更改。
dic.Remove("abc9");

我能保证这些值被检索到是这样的吗:"z1","abc9","abc8","ABC1"?不行 - I4V
不,虽然可能会让人感到困惑,因为现实生活中的字典当然是按字母顺序排列的 :) - Kieren Johnstone
除了表意文字语言之外…… :) - Jim Mischel
6
尝试使用该功能并不能回答该功能是否得到正式支持(因此将来是否会继续受到支持)。考虑到今天的实现只能证明其不被支持,而无法证明其被支持。 - Tormod
4个回答

6

根据MSDN(强调我的)的说明,为了枚举目的,字典中的每个项被视为一个KeyValuePair<TKey, TValue>结构,代表一个值和它的键。 返回项的顺序是未定义的。如果您想要更多地控制迭代顺序,则可以查看OrderedDictionary类。


5

简短回答是。在 Dictionary<TKey, TValue> 中不能保证顺序,也不应该指望能够维护顺序。

你可能想要查看 OrderedDictionary

例子:

OrderedDictionary d = new OrderedDictionary();

d.Add("01", "First");
d.Add("02", "Second");
d.Add("03", "Third");
d.Add("04", "Fourth");
d.Add("05", "Fifth");

for(int i = 0; i < d.Count; i++) // Print values in order
{
   Console.WriteLine(d[i]);
}

注意,由于某些奇怪的原因,没有通用的 OrderedDictionary<TKey,TValue> 版本。但是,这个问题 提供了一些实现方法的提示。

谢谢。我先问一下很好。OrderedDictionary 似乎是我需要的。那么你的意思是,如果我在上面的代码中将 Dictionary 替换为 OrderedDictionary,我的假设就成立了,对吗? - ahmd0
@ahmd0 - 正确,但是出于某种原因,似乎没有通用版本的 OrderedDictionary,所以您在访问每个值时必须进行强制转换。 - Mike Christensen
不,它们不一样。我刚刚验证了一下。像我上面展示的那个foreach循环虽然可以编译,但在使用OrderedDictionary而不是Dictionary时会崩溃。必须将其更改为foreach (DictionaryEntry de in dic){}。此外,正如你指出的那样,这些强制转换非常令人讨厌... - ahmd0
@ahmd0 - 是的,也许最好编写自己的实现。或者,Jon Skeet建议使用Dictionary<>加上一个List<>来跟踪顺序。 - Mike Christensen

1
我能保证这些值会被检索到吗: "z1", "abc9", "abc8", "ABC1"? 绝对不能。始终将Dictionary<,>视为无序的键/值对集合。即使作为实现细节,如果您只添加值,通常会按插入顺序查看它们,但是您不应该依赖于此。来自文档的说明: 对于枚举目的,字典中的每个项都被视为表示值及其键的KeyValuePair结构。返回项目的顺序未定义。(强调是我的。)
如果您需要特定的顺序,您应该使用不同的集合 - 可能与字典一起使用,如果您还需要能够按键进行提取。(例如,维护一个 IList 和一个 Dictionary 并不是完全不常见的做法。)

Jon,如果您从未删除或操作过字典,只是添加项目,那么底层实现似乎表明它们将按顺序排列,因为它是一个条目数组。这是否正确?我之前已经仔细研究过这个问题,但一直无法打破这个前提! - Allan Elder
2
@AllanElder:是的,这就是当前实现的方式。但你永远不应该依赖于它。 - Jon Skeet
1
@AllanElder - 许多错误都是因为假设某种行为永远不会改变而产生的。如果排序顺序不能保证,那么排序顺序就不能保证。我们所知道的是,.NET 6.0或.NET 12.0可能会完全重写Dictionary<>,从而导致多年后与编写不良代码不兼容。到那时,原始作者可能已经离开了,留下一些可怜的人来清理这个混乱(是的,我曾经是那个可怜的人)。 - Mike Christensen
@MikeChristensen:虽然有些人可能认为.NET已经拥有了太多的集合,但我希望看到.NET包含更多的“只添加”集合,因为这样的集合通常可以在最小的成本下提供昂贵的保证,而这种保证在允许更多变异的集合中是昂贵的。例如,在字典中维护插入顺序,如果从不删除任何内容,则成本很低;但在存在删除的情况下维护它则不是。与允许其他变异的集合相比,只添加集合的线程安全性也要便宜得多。 - supercat

0

不,没有元素顺序的保证。此外,它可能因 IDictionary<...> 接口的实际实现而有所不同。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接