2010-10-12 62 views
5

我想知道这件事,所以我想我会问它。GetHashCode平等

你会看到用于忽略equals作为GetHashCode的用于按成员平等相同的语义逻辑大部分地方......但是他们通常使用不同的实现:

public override bool Equals(object obj) 
    { 
     if (obj == null || GetType() != obj.GetType()) 
     { 
      return false; 
     } 
     var other = (MyType)obj; 
     if (other.Prop1 != Prop1) 
     { 
      return false; 
     } 
     return true; 
    } 

    public override int GetHashCode() 
    { 
     int hash = -657803396; 
     num ^= Prop1.GetHashCode(); 
     return num; 
    } 

如果你实现你的类型按成员平等(可以说在字典存储),为什么不重写则GetHashCode的推动在平等做这样的事情:

public override bool Equals(object obj) 
    { 
     return this.HashEqualsAndIsSameType(obj); 
    } 

    public static bool HashEquals(this object source, object obj) 
    { 
     if (source != null && obj != null) 
     { 
      return source.GetHashCode() == obj.GetHashCode(); 
     } 
     if (source != null || obj != null) 
     { 
      return false; 
     } 
     return true; 
    } 

    public static bool HashEqualsAndIsSameType<T>(this T source, object obj) 
    { 
     return (obj == null || obj.GetType() == typeof(T)) && source.HashEquals(obj); 
    } 

回答

10

因为存在冲突的真正风险。哈希码是而不是唯一。他们可以(在不同的情况下)证明不平等,但从不平等。当寻找一个项目:

  • 获得哈希码(S)
  • 如果哈希代码是不同的,对象是不同的;丢弃它
  • 如果哈希码是相同的,检查等于:
  • 如果报告的Equals他们true是相同
  • 别人丢弃

考虑long ......因为哈希码是int ,很容易看到有很多很多的冲突。

+0

那么你会如何建议用最少量的重复成员引用来实现成员级别的GetHashCode/Equals?这种重复可能导致意外遗漏,并造成重大问题(这是我今天提出的问题)。另外,如果我们想要一个对象的唯一校验和呢。是否存在一个好的接口,用于定义一个类型提供计算校验和的能力? – Jeff 2010-10-12 13:27:14

+0

@jeff它是非常罕见的,你需要,但像resharper这样的工具会为你做 – 2010-10-12 16:13:05

+0

一个例子 - 离线乐观缓存和/或各种类型的对象的锁定(换句话说,在一张桌子上没有列数据库使用版本ID进行标记)。客户端和服务器都需要一种计算哈希或校验和的方法(你可以称之为唯一的方法),这样如果客户端向服务器发送一个陈旧的版本,服务器就知道不保存它并且抛出一个例外。你将如何计算哈希/校验和为此目的? – Jeff 2010-10-12 18:07:53

1

哈希是不是1对1,你可以有多个不同的值散列为相同价值,但应该com不平等。所以你不能用GetHashCode来实现Equals。这就是为什么你在一个散列表中发生冲突,以及为什么一个散列表查找必须包含对GetHashCode和Equals的调用。