关于c#:自定义类型GetHashCode

Custom type GetHashCode

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicate:
What is the best algorithm for an overridden System.Object.GetHashCode?

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

1
2
3
4
protected override int GetHashCode()
{
    return str1.GetHashCode() + str2.GetHashCode() + str3.GetHashCode();
}

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


最好的方法是避免产生相同哈希代码的任何事情,如果您:

  • 交换了操作数的顺序
  • 有一个很大的零值,只需移动非零值

添加(本身)和XOR在这些帐户上都失败。

下面是一个更好的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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;
    }
}

无论您在代码中使用addition还是xor,都有待讨论,我已经看到了使用这两种方法的示例,但没有对哪一种方法进行明确的分析(即统一分布)。选择一个,然后跟着它走。

397是resharper加载项在生成gethashcode实现时使用的默认值,显然是选中的,因为它通常会溢出int的范围,从而更好地混合位。关于gethashcode实现的这种特定格式有很多理论,但它是最常用的一种。


我总是使用exclusive或(xor)而不是addition,因为它不倾向于在任何地方获取数字(比如大值)。所以我会这么说

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

是更好的实现。

你也可以尝试对它做一些改变,比如

1
2
3
4
5
6
7
8
protected override int GetHashCode()
{
    unchecked
    {
        return (str1.GetHashCode() * 1369) ^
               (str2.GetHashCode() * 37) ^ str3.GetHashCode();
    }
}

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