10

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

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。这是一个坏主意,如果是这样,我应该怎么做?

4

2 回答 2

10

自定义类的一个非常简单的哈希码方法是将每个字段的哈希码按位异或。它可以像这样简单:

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

上面的链接

XOR 具有以下很好的特性:

  • 它不依赖于计算顺序。
  • 它不会“浪费”比特。如果您在其中一个组件中更改一点,最终值也会发生变化。
  • 它很快,即使在最原始的计算机上也只有一个周期。
  • 它保持均匀分布。如果你组合的两块是均匀分布的,那么组合也是如此。换句话说,它不会倾向于将摘要的范围折叠成更窄的范围。

如果您希望字段中有重复值,则 XOR 不能很好地工作,因为重复值会在异或时相互抵消。由于您将三个不相关的字段散列在一起,在这种情况下这应该不是问题。

于 2009-07-02T01:53:11.663 回答
5

我认为您选择使用的方法没有问题。对哈希冲突的担忧“太多”几乎总是表明对问题的过度思考;只要哈希很可能不同,你就可以了。

Description如果可以合理地预期大多数时间对象可以根据它们的标题和出版日期(书籍?)来区分,那么最终你甚至可能想要考虑从你的哈希中省略掉。

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

于 2009-07-02T02:10:39.210 回答