为什么我需要在C#中重写.Equals和GetHashCode方法?

6

我正在使用Entity Framework 5。在我的C#代码中,我想比较两个对象是否相等。如果不相等,则要发出更新。

有人告诉我需要重写.Equals方法,然后还要重写gethascode方法。我的类看起来像这样:

public class Students    {
    public int PersonId { get; set; }
    public string Name { get; set; }
    public int Age {get; set;} 
}

有人能解释一下为什么我需要重写.Equals和.GetHashCode吗?同时,可以给我举一个例子吗?特别是我对哈希码不太确定。请注意,我的PersonId是这个类的唯一编号。


3
为什么在重写 Equals 方法时必须同时重写 GetHashCode 方法?因为 Equals 和 GetHashCode 方法在哈希表、字典等数据结构中经常被使用。在这些数据结构中,对象的比较和搜索通常是通过哈希码实现的。如果 Equals 方法被重写而 GetHashCode 方法没有被同步更新,则哈希表或字典可能无法正确地工作,从而导致意外的行为。因此,在重写 Equals 方法时,必须同时重写 GetHashCode 方法,以确保对象的一致性和正确性。 - Prabhu Murthy
@Melina,你在评论中多次询问为什么需要重写GetHashCode。请阅读@CodeIgnoto链接的问题的答案 - Hamish Smith
2个回答

3

出于各种原因,您需要覆盖这两个方法。例如,GetHashCode 方法用于在 DictionaryHashTable 中进行插入和查找。而 Equals 方法用于对象的任何相等性测试。例如:

public partial class myClass
{
  public override bool Equals(object obj)
  {
     return base.Equals(obj);
  }

  public override int GetHashCode()
  {
     return base.GetHashCode();
  }
}

对于GetHashCode,我会这样做:

  public int GetHashCode()
  {
     return PersonId.GetHashCode() ^ 
            Name.GetHashCode() ^ 
            Age.GetHashCode();
  }

如果您重写了GetHashCode方法,您也应该重写Equals方法,反之亦然。如果您重写的Equals方法在测试两个对象是否相等时返回true,则您重写的GetHashCode方法必须为这两个对象返回相同的值。

我认为他说过ID是唯一的。 - Mark Segal
是的,Id是唯一的。我能否只使用它作为哈希码,为什么需要创建一个GetHashCode方法?它如何被使用? - user1943020
@Melina 如果你正在使用哈希表、字典或其他类似的数据结构,那么 GetHashCode 方法会被调用以获取该类的哈希值。你可以仅从 ID 进行哈希计算,但这是你的选择。我会对所有成员进行哈希计算,但如果 ID 确实是唯一的,则这不是必需的。 - No Idea For Name
谢谢,但我一直听到“如果我覆盖.Equals”,那么我需要覆盖GetHashCode。所以,如果我通常不覆盖.Equals,我是否仍然需要覆盖.GetHashCode? - user1943020
@Melina 如果您不覆盖Equals,并且不使用字典、列表或其他数据结构,也不需要比较不同类型,则可能不需要覆盖这两个方法。否则,您应该这样做。如果您覆盖了Equals,则一定要覆盖hashCode。 - No Idea For Name
.NET BCL中的类依赖于具有一致实现的.Equals()和.GetHashCode() - 如果您不同时重载这两个方法,可能会出现非常奇怪的错误。请参阅http://blogs.msdn.com/b/ericlippert/archive/2011/02/28/guidelines-and-rules-for-gethashcode.aspx 了解更多信息。 - Bevan

1

类是引用类型。当您创建两个对象并将它们存储在变量中时,您只存储对它们的引用。这意味着如果您尝试比较它们,您将只比较两个引用,只有指向堆上相同对象的引用才会相等。如果您想改变这种行为,您需要覆盖 Equals
此外,一些集合依赖于 GetHashCode 来将元素存储在树状结构(或其他任何结构)中,需要某种比较给定类的两个对象的手段。这就是为什么如果您需要定义的类在指定情况下正确地运行,您需要实现这些方法的原因。
GetHashCode 的典型实现是类字段的异或值,这在 @No Idea For Name 的答案中已经给出。但由于在您的示例中 PersonId 是唯一的,您也可以使用它:

public int GetHashCode()
{
   return PersonId.GetHashCode();
}

谢谢。现在我明白了。至于GetHashCode,它为什么需要?如果我的Id是唯一的,你建议我如何编码它? - user1943020
@Melina,同样的原因。GetHashCode(针对对象)的默认实现基于引用比较。通常情况下,GetHashCode 应该表现出与 Equals 相同的行为(尽管存在哈希冲突)。 - harpo
@Melina,你只需返回PersonId的哈希码。我相信我已经解释过为什么必须重写它。如果还不清楚,请具体说明。 - atoMerz

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