【问题标题】:Dictionary.GetKey Returns False Even Though Key Is Present - GetHashCode/Equals Already Overridden即使存在密钥,Dictionary.GetKey 仍返回 False - GetHashCode/Equals 已被覆盖
【发布时间】:2014-09-10 00:39:50
【问题描述】:

这是在 C# 中。我有一个问题,即 Dictionary.ContainsKey 会返回 false,即使我知道密钥在其中。

很遗憾,我没有任何代码可显示。代码不容易拼凑起来;它分布在多个类中,并通过事件等触发。我编写的快速单元测试没有重现问题。

这是调试会话期间即时窗口的输出(添加了 cmets 并进行了更改以保护细节):

// 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 和 等于。
  • 字典构造为 new Dictionary() 没有额外的构造函数参数。
  • 通过调试,我已经验证了 键类型中的GetHashCode被调用,而不是Equals(obj)
  • 当 应用程序运行时,只加载了一个具有密钥类型的 DLL, 所以在不同版本的情况下可能不是同一类型的情况 同一个DLL

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

感谢您的帮助 - 我的想法已经用完了。

【问题讨论】:

    标签: c# dictionary keynotfoundexception


    【解决方案1】:

    用作键的类型已覆盖 GetHashCode 和 Equals 的方法。

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

    来自MSDN

    一般来说,对于可变引用类型,您应该仅在以下情况下覆盖 GetHashCode:

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

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

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

    【讨论】:

    • 确实如此。如果您在相关对象存储在字典(或任何类似 HashTable 的结构)中时改变参与 GetHashCode/Equality 比较的属性,您将破坏字典并且所有赌注都关闭。所有参与 GetHashCode 和 Equality 的属性都应该是不可变的。不要依赖文档。
    • 谢谢。但是,鉴于上面的即时窗口的所有输出都是在应用程序处于断点时获取的,并且哈希码相同,这似乎不太可能是问题所在。我错过了什么吗?
    • @ck: Dictionary 损坏发生在断点之前,即您在密钥进入字典后对其进行了变异,导致它生成与 Dictionary 使用的代码不同的代码存储它。是的,您可以枚举密钥,但是因为它们是针对不同的哈希码存储的,所以您找不到它。
    • @spender:好点子。为了测试这一点,我到达了相同的断点,然后在即时窗口中创建了一个 MyKey 的实例,它使用我期望字典中的键具有的相同属性值。即时窗口的新创建键和字典中的键具有相同的哈希码。
    • @ck:当然可以,但是字典中的键在字典中存储时是否具有相同的哈希码?否则,您的密钥查找将失败,因为该项目位于错误的哈希表存储桶中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-09
    • 1970-01-01
    相关资源
    最近更新 更多