我有一个包含字符串属性的类,我需要覆盖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();
}
最好的方法是什么?
答案 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
。通过连接字符串,可以以某些性能为代价来避免这种情况(如果您正在编写性能关键程序,我不会在内部循环中连接字符串。)
所以最后,我毕竟没有给出答案,原因很简单,实际上没有答案。这一切都取决于它的使用地点和方式。