正确实现GetHashCode

Ziv*_*vka 57 .net c# equals

我想听听社区关于如何为我的对象实现GetHashCode(或覆盖它)的消息.我理解如果我覆盖equals方法,我需要这样做.我已经实现了相当多的次数,有时只是调用基本方法.我知道如果对象包含相同的细节(成员),我的对象应该等于对象的另一个实例.从班级成员那里获取哈希码的最佳方法是什么?

jas*_*son 48

假设您的课程如下:

class Frob {
    public string Foo { get; set; }
    public int Bar { get; set; }
    public double FooBar { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

假设您定义了等于两个实例,Frob如果它们Foo和它们Bar相等,FooBar则无关紧要.

然后你应该GetHashCodeFoo和来定义Bar.一种方法是这样的:

return this.Foo.GetHashCode() * 17 + this.Bar.GetHashCode();
Run Code Online (Sandbox Code Playgroud)

基本上,您只想将所有用于定义相等性的字段合并.一种方法是像我一样继续累积和乘以17.它速度快,简单,正确,通常可以提供良好的分布.

  • 小心实现`GetHashCode()`(和`Equals()`)依赖于可变数据,就像这里一样.如果将此类对象放入基于哈希的字典中,然后将其变异,则字典将无法再正常工作.理想情况下,`GetHashCode()`(和`Equals()`)应该只依赖于不可变数据. (74认同)
  • 我觉得这应该是一个问题本身,但为什么23? (6认同)
  • 也许指出GetHashCode只告诉你两个对象**是否可能被视为相等.仍然存在哈希冲突的可能性. (6认同)
  • 我认为计算应该用`unchecked`关键字包装,如下所示:`unchecked(this.Foo.GetHashCode()*17 + this.Bar.GetHashCode())`.总和可能大于int.MaxValue. (5认同)
  • 我对这个17有疑问:为什么是17? (4认同)
  • @Tragedian:基本要求是GetHashCode必须反映Equals的行为。如果两个对象可能一时相等,但后来又可能不相等,反之亦然,则必须确保没有任何对此类对象的引用暴露于任何可能会意外更改其状态的情况。不幸的是,类型系统中没有任何东西可以表明这一点。 (3认同)
  • @Quintus:我已经纠正了。当分配`Bar = int.MaxValue; Foo = "something"`,运行`GetHashCode()` 函数并且没有`unchecked` 关键字,代码将运行并产生一个负哈希码并且不会崩溃,因此`unchecked` 关键字不是必需的 (3认同)
  • @user904963 1.人们必须在某个地方学习“常识”。如果他们正在看这个问题,我认为他们很有可能还没有学会。2. `GetHashCode` 的重点是使用哈希值,所以我认为突出显示问题的常见来源是有用的。3.问题是“正确实现GetHashCode”,因此是相关的。 (3认同)
  • @Tragedian:.NET没有工具来实际控制突变。要求不变性是没有用的,也不实用,因此-通常,您将需要未突变的数据,而不是无法突变的数据。当然,在“只读”成员很实用的情况下-一定要使用它们-只是不要指望它在任何地方都是实用的。 (2认同)
  • @mortb-我的理解是,仅当在编译时可以检测到上溢/下溢时(即,表达式仅包含常量),才应用未选中的选项。包含非常量术语的表达式默认为未选中。 (2认同)