GetHashCode()的返回值应该基于原始对象的状态还是修改后的对象的状态?

时间:2012-10-17 21:45:23

标签: c# generics dictionary gethashcode iequatable

我最近以几种不同的方式问过这个问题,但是没有得到一个答案,告诉我当我持有对变化的引用{{1}时,需要如何处理<T,U>字典。 }}。出于此问题的目的,“状态”指的是在检查T.GetHashCode()时也检查的属性和字段。假设包括所有公共,内部和受保护的成员。

鉴于我有一个C#对象

  • 覆盖GetHashCode和Equals

  • 此对象作为键值保存到Dictionary中(请注意,我的理解是Dictionary将在此时读取GetHashCode值)

  • 我按键搜索对象并修改一个值。 (修改此值会修改我的自定义等于函数和可能的gethashcode)

我的问题是,GetHashCode应该反映什么?该函数的返回是否应反映对象的原始状态或修改后的状态?

示例代码

Equals()

基于this answer from Jon Skeet(我之前的问题)

  

“如果我更改最终会更改密钥值的属性,我该怎么办?” - 我

  

“基本上,你被塞满了。你不会(或者至少可能不会)   能够在你的字典中再次找到该密钥。你应该避免这种情况   尽可能仔细。就个人而言,我通常会发现   适合字典键的类好   不可变性的候选人。“ - J.S。

这是否意味着我需要从Dictionary中删除对象并重新添加它?这是正确/最好的方式吗?

2 个答案:

答案 0 :(得分:2)

好的,所以澄清一下:你正在修改键/值对的部分。

现在问题很明确,答案相对简单:

  

这是否意味着我需要从Dictionary中删除对象并重新添加它?

是。 但是 - 您必须在修改它之前将其删除。所以你要写:

testDictionary.Add(keyValue, "some data");
// Do whatever...

testDictionary.Remove(keyValue);
te.EntryName = "modified data";
testDictionary.Add(keyValue, "some data"); // Or a different value...

一般来说,只使用不可变数据结构作为字典键,<​​em>远风险较小。

另请注意,目前您的Equals方法依赖于引用所涉及的两个列表的相等性 - 这真的是您想要的吗?另外,您并未覆盖GetHashCode中的TrustedEntity,所以即使您 创建了一个具有相同列表的新TrustedEntity,它也不会给您你想要的结果。基本上,不清楚你想要什么样的平等操作 - 你需要向自己澄清这一点,然后理想地创建所涉及数据的不可变表示。

答案 1 :(得分:1)

GetHashCode()是否应该改变的问题有点像红鲱鱼。我建议六个公理:

  1. 应始终观察每个物体与自身相等。
  2. 如果一个对象被观察到与另一个对象相等,则两个对象应该永远报告自己彼此相等。
  3. 如果一个物体被观察到与另一个物体不相等,那么这两个物体应该永远报告自己与另一物体不相等。
  4. 如果一个对象被观察到与另一个对象相等,并且任何一个被观察到等于三分之一,那么它们应该永远更多地报告自己等于第三个对象。
  5. 如果一个对象被观察到与另一个对象相等,并且观察到任何一个对象不等于三分之一,则两者都应该永远报告自己与第三个对象不相等。
  6. 观察对象的哈希码代表了一种观察结果,即它与每个返回不同哈希码的对象不相等。

对象的哈希码不改变的要求不是公理之一,而是来自点#1和#6;观察一个与先前观察不同的对象的哈希码将构成一个观察到该对象与其自身不相等。