自定义类型GetHashCode

时间:2011-02-20 21:03:39

标签: c# .net

  

可能重复:
  What is the best algorithm for an overridden System.Object.GetHashCode?

我需要为包含三个字符串的类型重写GetHashCode方法。这是我的代码:

protected override int GetHashCode()
{
    return str1.GetHashCode() + str2.GetHashCode() + str3.GetHashCode();
}

这种方法实现的安全方法是什么?

2 个答案:

答案 0 :(得分:18)

最好的方法是避免在下列情况下产生相同哈希码的任何内容:

  • 交换了操作数的顺序
  • 的值大部分为零,只需移动
  • 周围的非零值

这些帐户的添加(单独)和XOR都失败。

这是一个更好的方法:

public override int GetHashCode()
{
    unchecked
    {
        int result = 37; // prime

        result *= 397; // also prime (see note)
        if (str1 != null)
            result += str1.GetHashCode();

        result *= 397;
        if (str2 != null)
            result += str2.GetHashCode();

        result *= 397;
        if (str2 != null)
            result += str2.GetHashCode();

        return result;
    }
}

无论你在代码中使用加法还是异或都有争议,我已经看到使用两者的例子,没有明确分析哪些是优越的(即均匀分布)。选择一个并继续使用它。

397是ReSharper addin when it generates GetHashCode implementations使用的默认值,显然是选中的,因为它通常会溢出int的范围,从而更好地混合位。围绕这种特定格式的GetHashCode实现有很多理论,但它是最常用的。

答案 1 :(得分:4)

我总是使用exclusive或(Xor)而不是添加,因为它不具有在任何地方获取数字的倾向(比如朝向大值)。所以我会说那个

protected override int GetHashCode()
{ return str1.GetHashCode() ^ str2.GetHashCode() ^ str3.GetHashCode(); }

是一种更好的实施方式。

您也可以尝试使用其中的变体,例如

protected override int GetHashCode()
{
    unchecked
    {
        return (str1.GetHashCode() * 1369) ^
               (str2.GetHashCode() * 37) ^ str3.GetHashCode();
    }
}

如果要确保切换字符串的值会产生不同的结果。有各种各样的方法可用于散列(例如universal hashing),所以只需搜索散列方法,如果这就是你要找的东西。