Dictionary.GetKey返回false,尽管键存在 - GetHashCode / Equals已被覆盖

3
这是在C#中的问题。我的问题是,即使我知道键存在,Dictionary.ContainsKey返回false。
很不幸,我没有任何代码可展示。这段代码不容易整合在一起;它分散在多个类中,并通过事件等方式触发。我编写的一个快速单元测试无法复现这个问题。
以下是调试会话期间立即窗口的输出(添加了注释并更改以保护细节):
// throws KeyNotFoundException
myDict[key]  

// throws KeyNotFoundException
myDict[new MyKey("SomeString .1", "SomeOtherString", SomeEnum.Foo)]

// Element [5] is the key
myDict.Keys
Count = 10
    [0]: {...}
    [1]: {...}
    [2]: {...}
    [3]: {...}
    [4]: {...}
    [5]: {Foo SomeOtherString SomeString  .1}
    [6]: {...}
    [7]: {...}
    [8]: {...}
    [9]: {...}

// Get key at element [5]   
enumerator.Current
{Foo SomeOtherString SomeString  .1}
    [My.Namespace.KeyType]: {Foo SomeOtherString SomeString  .1}
    SomeEnum: Foo
    SomeOtherStringProperty: "SomeOtherString"

// key used to do lookup
key
{Foo SomeOtherString SomeString  .1}
    [My.Namespace.KeyType]: {Foo SomeOtherString SomeString  .1}
    SomeEnum: Foo
    SomeOtherStringProperty: "SomeOtherString"

// hash codes of key in dictionary matches hash code of lookup key
enumerator.Current.GetHashCode()
193014103
key.GetHashCode()
193014103

一些额外的注意事项:

  • 用作键的类型已覆盖 GetHashCode 和 Equals 方法。
  • 使用 new Dictionary() 构造字典时没有传递额外的构造参数。
  • 通过调试,我已经验证了键类型中的 GetHashCode 被调用了,但没有调用 Equals(obj)。
  • 当应用程序运行时,只有一个加载了具有键类型的 DLL,因此这可能不是同一 DLL 的不同版本的情况。

有人知道为什么会发生这种情况吗?

感谢任何帮助-我已经没有更多的想法了。

1个回答

4

作为键使用的类型已经覆盖了 GetHashCode 和 Equals 方法。

这是我要检查的第一件事。如果哈希码基于可变值,它肯定会导致此问题。

来自 MSDN

通常情况下,对于可变引用类型,只有在以下情况下应该重写 GetHashCode:

  • 您可以从不可变字段计算哈希码;或

  • 您可以确保可变对象的哈希码在包含依赖其哈希码的集合中时不会更改。

否则,您可能会认为可变对象在哈希表中丢失了。如果您选择为可变引用类型重写 GetHashCode,则您的文档应明确说明,在对象存储在哈希表中时,用户不应修改对象值。


确实。如果当对象存储在字典(或任何类似哈希表的结构)中时,更改参与 GetHashCode/Equality 比较的属性,将会破坏该字典,并且一切都无法预料。所有参与 GetHashCode 和 Equality 的属性都应该是不可变的。不要依赖文档来做到这一点。 - spender
谢谢。然而,考虑到上面立即窗口的所有输出都是在应用程序被置于断点时进行的,并且哈希码是相同的,因此似乎这不是问题的原因。我有什么遗漏吗? - ck.
1
@ck:在断点之前发生了字典损坏,即在将键放入字典后对其进行了变异,导致生成的代码与字典用于存储它的代码不同。是的,您可以枚举键,但由于它们存储在不同的哈希码下,因此无法找到它。 - spender
@spender:好观点。为了测试这一点,我到达了同一个断点,然后在即时窗口中创建了一个MyKey的实例,使用了与我期望字典中的键具有相同的属性值。即时窗口中新创建的键和字典中的键具有相同的哈希码。 - ck.
@ck:当时存储在字典中的键是否具有相同的哈希码?如果不是,您的键查找将失败,因为该项位于错误的哈希表桶中。 - spender
检出代码后,我认为你是正确的 - 感谢你的帮助! - ck.

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