如何计算具有字符串属性的类的哈希码?最佳方法是什么?

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();
}

什么是最好的方式?

5
可能会有帮助 [GetHashCode的指南和规则-Eric Lippert](http://blogs.msdn.com/b/ericlippert/archive/2011/02/28/guidelines-and-rules-for-gethashcode.aspx) - Habib
@Habib 谢谢,这真的是非常有用的资源,但问题仍然存在。从文章中我发现,GetHashCode() 方法应该尽可能快速且独特(但不是必须的)。因此,第一个想法似乎更快,但第二个想法更独特(它将提供更少的碰撞数)。我相信这两个想法都是适用的,但了解其他开发人员的想法会很棒。 - Warlock
这里有通用的哈希实现者 https://dev59.com/EnVC5IYBdhLWcg3wihqv?lq=1,这可以帮助你处理`string`属性。 - nawfal
2个回答

4
你不应该只是简单地将它们进行异或操作,因为这不考虑顺序。想象一下你有两个对象:
"foo", "bar", "baz"

并且

"bar", "foo", "baz"

通过简单的异或运算,这两个哈希值将会相同。幸运的是,解决这个问题还是比较容易的。以下是我用来合并哈希值的代码:

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 具有相当强大的哈希值组合功能可供使用。


负的哈希码是否是个问题?(未检查的子句) - Royi Namir

3
只需将每个字符串的哈希值进行异或运算。与字符串连接相比,它更加便宜(性能方面),就我所见,它并不更容易发生冲突。假设每个字符串都有5个字符长,每个字符占用1个字节。在第一个方法中,您将15个字节哈希为4个字节(整数)。在第二个方法中,您将所有3个字符串(一项昂贵的操作)连接起来,最终得到一个15字节的字符串,然后对其进行哈希处理以得到4个字节。两种方法都将15个字节转换为4个字节,因此理论上在碰撞方面两者相似。
实际上,碰撞概率确实存在差异,但在实践中可能并不总是重要的。这取决于字符串将具有的数据。如果所有3个字符串都相等,并且它们的哈希值都为0001(我只是为了举例而使用了一个简单的数字),则通过对前两个字符串进行异或运算,您将得到0000,然后将第三个字符串与其进行异或运算,将会回到0001。通过连接字符串可以避免这种情况,但代价是一些性能损失(如果您正在编写性能关键程序,则不应该在内部循环中连接字符串)。
因此,最终,我并没有真正给出答案,原因很简单,因为实际上并没有答案。一切都取决于它将在何处以及如何使用。

另一种表述方式是XOR是可结合的,这意味着顺序并不重要。这意味着对于任何给定的字符串集,无论分配给给定字符串的属性如何,您都将获得相同的哈希代码。这并不会使答案变得糟糕,但这是需要考虑的一个警告。 - Technetium

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接