为啥 ReSharper GetHashCode 覆盖使用“397”?

Posted

技术标签:

【中文标题】为啥 ReSharper GetHashCode 覆盖使用“397”?【英文标题】:Why is '397' used for ReSharper GetHashCode override?为什么 ReSharper GetHashCode 覆盖使用“397”? 【发布时间】:2010-09-11 06:59:52 【问题描述】:

和你们中的许多人一样,我使用 ReSharper 来加快开发过程。当您使用它来覆盖类的相等成员时,它为GetHashCode() 生成的代码生成如下:

    public override int GetHashCode()
    
        unchecked
        
            int result = (Key != null ? Key.GetHashCode() : 0);
            result = (result * 397) ^ (EditableProperty != null ? EditableProperty.GetHashCode() : 0);
            result = (result * 397) ^ ObjectId;
            return result;
        
    

当然我有一些自己的成员,但我想知道为什么是 397?

编辑:所以我的问题的措辞会更好,397 素数除了是素数之外还有什么“特殊”吗?

【问题讨论】:

【参考方案1】:

可能是因为 397 是一个足够大的素数,会导致结果变量溢出并在一定程度上混合散列位,从而提供更好的散列码分布。 397 并没有什么特别之处可以将它与其他相同大小的素数区分开来。

【讨论】:

而 397 很高兴。难道我们不都只想快乐吗? 好的,但是为什么它必须是素数,为什么它必须是那个精确的量级?如果它必须是素数,为什么不是 2 或 2147483647?我猜想得到很好的突变(这种乘法的唯一原因是突变)我们不需要数字是素数。我们需要乘数具有相对相同的数字或零和一,最好没有明确的模式。 397=110001101b 符合。仍然不确定幅度。 正如尼克所说,它并没有什么特别之处。它不需要那么大,这只是一个足够大的数字,当您计算哈希时,结果会溢出(因为 GetHashCode() 返回一个 Int32)。选择素数只是对分布有帮助,我没有数学学位,所以我不会尝试解释它,但是乘以素数的结果比乘以任何其他任意数字的结果分布得更好。 @AndriyK 2 是一个非常小的哈希表。您的负载因子将是基于素数的哈希表大小的最小负载因子。随着负载因子接近 0,哈希表中未使用区域的比例增加,但搜索成本不一定降低。所以它实际上是哈希表的最差大小。换句话说,您可以将* 397 视为定义哈希表的大小,这就是 FNV 哈希算法所做的(但它建议 1099511628211 用于 64 位 哈希,它不会适用于 32 位整数)。【参考方案2】:

resharper 使用的哈希看起来像是FNV 哈希的变体。 FNV 经常使用不同的素数来实现。 There's a discussion on the appropriate choice of primes for FNV here.

【讨论】:

以上是关于为啥 ReSharper GetHashCode 覆盖使用“397”?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我们需要在对象模型项目中使用 GetHashCode() 函数? [复制]

为啥我需要覆盖 C# 中的 .Equals 和 GetHashCode [重复]

为啥覆盖 .GetHashCode 会清除 WinForms 中的这些数据绑定值?

为啥 ReSharper 告诉我“隐式捕获的闭包”?

为啥代码覆盖率在 ReSharper 中不起作用?

为啥 Resharper 将此标记为“访问修改后的闭包”?