使用字符串属性计算类的哈希码的最佳方法是什么?

时间:2012-11-28 05:39:23

标签: c# gethashcode

我有一个包含字符串属性的类,我需要覆盖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();
}

最好的方法是什么?

2 个答案:

答案 0 :(得分: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具有非常强大的哈希组合,您可以拉。

答案 1 :(得分:3)

将每个字符串的哈希值混合在一起。它比字符串连接更便宜(性能明智),据我所知,它不容易发生冲突。假设每个字符串长度为5个字符,每个字符占用1个字节。在第一个中,您将散列15个字节到4个字节(int)。在第二个中,您将连接所有3个字符串(一个昂贵的操作),最后得到一个15字节的字符串,然后将它们哈希到4个字节。两者都将15个字节转换为4个,因此理论上的 在碰撞方面都非常相似。

实际上 碰撞的可能性有点不同,但在实践中它可能并不总是重要的。这取决于字符串将具有的数据。如果所有3个字符串相等并且它们每个都散列到0001(我仅仅为了示例而使用了一个简单的数字)。如果所有3都相等,那么前两个xoring将获得0000并且使用第三个xoring将返回0001。通过连接字符串,可以以某些性能为代价来避免这种情况(如果您正在编写性能关键程序,我不会在内部循环中连接字符串。)

所以最后,我毕竟没有给出答案,原因很简单,实际上没有答案。这一切都取决于它的使用地点和方式。