为什么在重写Equals方法时重写GetHashCode很重要?

为什么在重写Equals方法时重写GetHashCode很重要?

鉴于以下课程

public class Foo{
    public int FooId { get; set; }
    public string FooName { get; set; }

    public override bool Equals(object obj)
    {
        Foo fooItem = obj as Foo;

        return fooItem.FooId == this.FooId;
    }

    public override int GetHashCode()
    {
        // Which is preferred?

        return base.GetHashCode();

        //return this.FooId.GetHashCode();
    }}

我已经覆盖了该Equals方法,因为它Foo代表了Foos表的一行。哪个是覆盖的首选方法GetHashCode

覆盖为什么重要GetHashCode


qq_花开花谢_0
浏览 867回答 4
4回答

慕侠2389804

是的,重要的是,您的项目将用作字典中的键,或者HashSet<T>等等 - 因为这是用于(在没有自定义的情况下IEqualityComparer<T>)将项目分组到存储桶中。如果两个项的哈希码不匹配,它们可能永远不会被认为是相等的(Equals将永远不会被调用)。该GetHashCode()方法应反映Equals逻辑;&nbsp;规则是:如果两个东西相等(Equals(...) == true)那么它们必须返回相同的值GetHashCode()如果GetHashCode()是相等的,它是不必要对他们是相同的;&nbsp;这是一次碰撞,Equals将被调用以查看它是否是真正的平等。在这种情况下,看起来“&nbsp;return FooId;”是一个合适的GetHashCode()实现。如果您正在测试多个属性,通常使用下面的代码组合它们,以减少对角线冲突(即,new Foo(3,5)具有不同的哈希码new Foo(5,3)):unchecked&nbsp;//&nbsp;only&nbsp;needed&nbsp;if&nbsp;you're&nbsp;compiling&nbsp;with&nbsp;arithmetic&nbsp;checks&nbsp;enabled{&nbsp;//&nbsp;(the&nbsp;default&nbsp;compiler&nbsp;behaviour&nbsp;is&nbsp;*disabled*, &nbsp;so&nbsp;most&nbsp;folks&nbsp;won't&nbsp;need&nbsp;this) &nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;hash&nbsp;=&nbsp;13; &nbsp;&nbsp;&nbsp;&nbsp;hash&nbsp;=&nbsp;(hash&nbsp;*&nbsp;7)&nbsp;+&nbsp;field1.GetHashCode(); &nbsp;&nbsp;&nbsp;&nbsp;hash&nbsp;=&nbsp;(hash&nbsp;*&nbsp;7)&nbsp;+&nbsp;field2.GetHashCode(); &nbsp;&nbsp;&nbsp;&nbsp;... &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;hash;}哦 - 为了方便起见,你也可以考虑提供==和!=操作员覆盖Equals和GetHashCode。当你弄错了会发生什么事的证明就在这里。

白猪掌柜的

实际上很难GetHashCode()正确实现,因为除了Marc已经提到的规则之外,哈希代码在对象的生命周期内不应该改变。因此,用于计算哈希码的字段必须是不可变的。当我使用NHibernate时,我终于找到了解决这个问题的方法。我的方法是从对象的ID计算哈希码。只能通过构造函数设置ID,因此如果要更改ID,这是非常不可能的,您必须创建一个具有新ID的新对象,因此需要新的哈希代码。这种方法最适用于GUID,因为您可以提供随机生成ID的无参数构造函数。

绝地无双

通过重写Equals,您基本上声明自己是更了解如何比较给定类型的两个实例的人,因此您很可能是提供最佳哈希码的最佳候选者。这是ReSharper如何为您编写GetHashCode()函数的示例:public&nbsp;override&nbsp;int&nbsp;GetHashCode(){ &nbsp;&nbsp;&nbsp;&nbsp;unchecked &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;result&nbsp;=&nbsp;0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result&nbsp;=&nbsp;(result&nbsp;*&nbsp;397)&nbsp;^&nbsp;m_someVar1; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result&nbsp;=&nbsp;(result&nbsp;*&nbsp;397)&nbsp;^&nbsp;m_someVar2; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result&nbsp;=&nbsp;(result&nbsp;*&nbsp;397)&nbsp;^&nbsp;m_someVar3; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result&nbsp;=&nbsp;(result&nbsp;*&nbsp;397)&nbsp;^&nbsp;m_someVar4; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;result; &nbsp;&nbsp;&nbsp;&nbsp;}}正如您所看到的,它只是试图根据类中的所有字段猜测一个好的哈希代码,但是既然您知道对象的域或值范围,您仍然可以提供更好的哈希代码。
打开App,查看更多内容
随时随地看视频慕课网APP