字典键集奇怪
本文关键字:字典 | 更新日期: 2023-09-27 18:04:40
我有一个涉及字典的神秘情况,我从字典中枚举键,但是字典并不包含它声称包含的一些键。
Dictionary<uint, float> dict = GetDictionary(); // Gets values, 6268 pairs
foreach(uint key in dict.Keys)
{
if (!dict.ContainsKey(key))
Console.WriteLine("Wat? "+key);
}
上面的代码将打印6268个键中的两个。这两个键没有什么特别之处,都是小于Int32的正值。MaxValue(369099203和520093968).
对计数的检查显示如下:
Console.WriteLine(dict.Count); // 6268
Console.WriteLine(dict.Keys.Count()); // 6268
Console.WriteLine(dict.Keys.Count(dict.Keys.Contains)); // 6266
这是在。net4.5 CLR下运行的单线程 . net代码。字典是一个普通的Dictionary<uint, float>
,即没有自定义相等比较器。我假设有一个哈希问题发生,因为int/int的差异,但ContainsKey(key)
不应该保证为真所有键返回在字典的键集合?特别是当您只查看较低代码片段中的KeyCollection对象时,总数和包含对象的计数是关闭的,这感觉像是一个奇怪的ICollection
行为。
正如预期的那样,似乎有一个合理的解释:集合在其初始化期间被两个并发线程较早地修改了。当某物"有时断了",这是一个穿线问题,这是肯定的。显然,从多个线程访问字典可能会扰乱内部状态,使其在其生命周期的剩余时间内仅处于半功能状态,但不会引起任何异常。
我要切换到并发字典,可能会删除这个问题。谢谢。
我没有足够的代表来评论-但我确实试图重现你的问题,但无济于事。我建议你发布GetDictionary()是如何工作的,我也建议不要像这样迭代字典,而是执行下面的操作,看看是否可以修复它:
foreach (KeyValuePair<uint, float> pair in dict)
Console.WriteLine("[" + pair.Key + "]=" + pair.Value);
是否有机会在构造字典时添加自定义键相等比较器?如果是,问题可能与比较器实现有关。
重要提示:当我在这篇文章中提到GetHashCode
时,我指的是IEqualityComparer<T>.GetHashCode
的结果。默认情况下,字典将使用EqualityComparer<T>.Default
,它将返回对键本身调用GetHashCode
的结果。但是,您可以在创建字典时提供IEqualityComparer<T>
的特定实现,以使用不同的行为。
如果键的GetHashCode
结果在将值添加到字典和枚举键的点之间发生了变化,则会发生这种情况。当您枚举键时,它返回数组中所有填充的"bucket"的键。但是,当您查找特定的键时,它会从GetHashCode
的结果中重新计算预期的桶。如果哈希码改变了,那么键/值对在字典桶中的实际位置和期望位置可能不再相同,在这种情况下Contains
将返回false。
您应该确保字典中键的GetHashCode
结果在键的值被添加到字典后不会改变。
我在System中遇到了类似的奇怪行为。Uri。
原来是存储在字典中的键和我用来查找的键之间的架构不匹配。特别是,存储在字典中的Uri是32位的,而我正在寻找一个64位的。显然,由于GetHashcode()在不同的体系结构之间不被授予相等,因此字典无法匹配键。