7

我有一个带有字符串属性的类,我需要重写 GetHashCode() 方法。

class A
{
    public string Prop1 { get; set; }
    public string Prop2 { get; set; }
    public string Prop3 { get; set; }
}

第一个想法是做这样的事情:

public override int GetHashCode()
{
    return Prop1.GetHashCode() ^ Prop2.GetHashCode() ^ Prop3.GetHashCode();
}

第二个想法是:

public override int GetHashCode()
{
    return String.Join(";", new[] {Prop1, Prop2, Prop3}).GetHashCode();
}

什么是最好的方法?

4

2 回答 2

4

您不应该只是将它们异或在一起,因为这不考虑排序。假设你有两个对象:

"foo", "bar", "baz"

"bar", "foo", "baz"

使用简单的 XOR,这两者将具有相同的哈希值。幸运的是,它很容易解决。这是我用来组合哈希的代码:

static int MultiHash(IEnumerable<object> items)
{
    Contract.Requires(items != null);

    int h = 0;

    foreach (object item in items)
    {
         h = Combine(h, item != null ? item.GetHashCode() : 0);
    }

    return h;
}

static int Combine(int x, int y)
{
    unchecked
    {
         // This isn't a particularly strong way to combine hashes, but it's
         // cheap, respects ordering, and should work for the majority of cases.
         return (x << 5) + 3 + x ^ y;
    }
}

有很多方法可以组合散列,但通常像这样非常简单的东西就可以了。如果由于某种原因它不适用于您的情况,MurmurHash具有非常强大的哈希组合,您可以提取。

于 2012-12-10T16:54:31.523 回答
3

只需将每个字符串的哈希值进行异或运算即可。它比字符串连接更便宜(性能方面),据我所知,它不太容易发生冲突。假设每个字符串有 5 个字符长,每个字符占用 1 个字节。在第一个中,您将 15 个字节散列到 4 个字节(int)。在第二个中,您将连接所有 3 个字符串(一项昂贵的操作)以最终得到一个 15 字节的字符串,并且您将其散列为 4 个字节。两者都将 15 个字节转换为 4 个字节,因此理论上两者在冲突方面非常相似。

实际上,碰撞的概率存在一些差异,但实际上它可能并不总是很重要。这取决于字符串将具有的数据。如果所有 3 个字符串都相等并且它们每个都散列到0001(我只是为了示例而使用一个简单的数字)。如果所有 3 个都相等,那么对前两个进行异或运算会得到你0000,而对第三个进行异或运算会让你回到0001. 通过连接字符串可以避免以牺牲一些性能为代价(如果您正在编写性能关键程序,我不会在内部循环中连接字符串)。

所以最后,我毕竟没有真正给出答案,原因很简单,真的没有。这一切都取决于它将在何处以及如何使用。

于 2012-12-10T15:48:14.973 回答