为什么 Visual Studio 将“-1937169414”添加到生成的哈希码计算中?

Sed*_*glu 12 c# visual-studio

如果您使用 Visual Studio 自己的重构菜单将 GetHashCode 实现添加到这样的类:

生成 GetHashCode 菜单

并选择类中唯一的 int 属性:

会员选择画面

它在 .NET Framework 上生成此代码:

public override int GetHashCode()
{
    return -1937169414 + Value.GetHashCode();
}
Run Code Online (Sandbox Code Playgroud)

(它HashCode.Combine(Value)在 .NET Core 上生成,我不确定它是否涉及相同的值)

这个值有什么特别之处?为什么不Value.GetHashCode()直接使用Visual Studio ?据我了解,它并没有真正影响哈希分布。由于它只是加法,连续的值仍然会累积在一起。

编辑:我只在不同的类中尝试过这个,Value但显然属性名称会影响生成的数字。例如,如果您将属性重命名为Halue,则数字变为 387336856。感谢 Gökhan Kurt 指出这一点。

phu*_*clv 5

如果你在微软的存储库中查找,-1521134295你会发现它出现了很多次

大部分搜索结果都在GetHashCode函数中,但都是以下形式

int hashCode = SOME_CONSTANT;
hashCode = hashCode * -1521134295 + field1.GetHashCode();
hashCode = hashCode * -1521134295 + field2.GetHashCode();
// ...
return hashCode;
Run Code Online (Sandbox Code Playgroud)

第一个hashCode * -1521134295 = SOME_CONSTANT * -1521134295将在生成器的生成期间或 CSC 的编译期间进行预乘。-1937169414这就是你的代码中的原因

深入研究结果揭示了代码生成部分,可以在函数CreateGetHashCodeMethodStatements中找到

const int hashFactor = -1521134295;

var initHash = 0;
var baseHashCode = GetBaseGetHashCodeMethod(containingType);
if (baseHashCode != null)
{
    initHash = initHash * hashFactor + Hash.GetFNVHashCode(baseHashCode.Name);
}

foreach (var symbol in members)
{
    initHash = initHash * hashFactor + Hash.GetFNVHashCode(symbol.Name);
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,哈希值取决于符号名称。在该函数中,也称为常量permuteValue,可能是因为在乘法之后,位以某种方式排列

// -1521134295
var permuteValue = CreateLiteralExpression(factory, hashFactor);
Run Code Online (Sandbox Code Playgroud)

如果我们以二进制形式查看值,就会发现一些模式:101001 010101010101010 101001 0100110100 1010101010101010 10100 10100 1。但是,如果我们将任意值与其相乘,那么就会有很多重叠的进位,所以我看不出它是如何工作的。输出也可能具有不同数量的设置位,因此它并不是真正的排列

您可以在 Roslyn 的AnonymousTypeGetHashCodeMethodSymbol中找到另一个生成器,它调用常量HASH_FACTOR

//  Method body:
//
//  HASH_FACTOR = 0xa5555529;
//  INIT_HASH = (...((0 * HASH_FACTOR) + GetFNVHashCode(backingFld_1.Name)) * HASH_FACTOR
//                                     + GetFNVHashCode(backingFld_2.Name)) * HASH_FACTOR
//                                     + ...
//                                     + GetFNVHashCode(backingFld_N.Name)
Run Code Online (Sandbox Code Playgroud)

选择该值的真正原因尚不清楚