我应该如何实现Object.GetHashCode()以实现复杂的相等?

时间:2009-07-02 01:09:45

标签: c# equals gethashcode iequatable

基本上,到目前为止,我有以下内容:

class Foo {
    public override bool Equals(object obj)
    {
        Foo d = obj as Foo ;
        if (d == null)
            return false;

        return this.Equals(d);
    }

    #region IEquatable<Foo> Members

    public bool Equals(Foo other)
    {
        if (this.Guid != String.Empty && this.Guid == other.Guid)
            return true;
        else if (this.Guid != String.Empty || other.Guid != String.Empty)
            return false;

        if (this.Title == other.Title &&
            this.PublishDate == other.PublishDate &&
            this.Description == other.Description)
            return true;

        return false;
    }
}

所以,问题是:我有一个非必需字段Guid,这是一个唯一标识符。如果没有设置,那么我需要尝试根据不太准确的度量确定相等性,以尝试确定两个对象是否相等。这很好,但它让GetHashCode()凌乱......我应该怎么做呢?一个天真的实现将是这样的:

public override int GetHashCode() {
    if (this.Guid != String.Empty)
        return this.Guid.GetHashCode();

    int hash = 37;
    hash = hash * 23 + this.Title.GetHashCode();
    hash = hash * 23 + this.PublishDate.GetHashCode();
    hash = hash * 23 + this.Description.GetHashCode();
    return hash;
}

但是这两种哈希冲突的可能性有多大?当然,我不希望它是1 in 2 ** 32。这是一个坏主意,如果是这样,我该怎么做呢?

2 个答案:

答案 0 :(得分:7)

一个非常简单的hash code method for custom classes是对每个字段的哈希码进行按位异或。它可以这么简单:

int hash = 0;
hash ^= this.Title.GetHashCode();
hash ^= this.PublishDate.GetHashCode();
hash ^= this.Description.GetHashCode();
return hash;

来自link above

  

XOR具有以下不错的属性:

     
      
  • 它不依赖于计算顺序。
  •   
  • 它不会“浪费”比特。如果您在其中一个组件中更改了一位,则最终值将会更改。
  •   
  • 即便是最原始的计算机,它也很快,一个循环。
  •   
  • 保持均匀分布。如果你组合的两个部分是均匀分布的,那么组合就是这样。换句话说,它不会将摘要的范围缩小到更窄的范围。
  •   

如果您希望在字段中具有重复值,则XOR不能正常工作,因为重复值会在XORed时相互抵消。因为你在一起散列三个不相关的字段,在这种情况下不应该是一个问题。

答案 1 :(得分:5)

我认为您选择使用的方法不存在问题。担心“太多”哈希冲突几乎总是表明过度思考问题;只要散列很可能不同,你应该没问题。

最终,如果可以合理地预期大部分时间对象可以根据其标题和出版日期(书籍?)进行区分,您甚至可能会考虑从您的哈希中省略Description。< / p>

你甚至可以考虑完全忽略你的哈希函数中的GUID,并且只在Equals实现中使用它来消除不太可能的(?)哈希冲突的情况。