1588575300
If you use Visual Studio’s own refactoring menu to add a GetHashCode implementation to a class like this:
and select the only int property in the class:
it generates this code on .NET Framework:
public override int GetHashCode()
{
return -1937169414 + Value.GetHashCode();
}
(it generates HashCode.Combine(Value)
on .NET Core instead, which I’m not sure if it involves the same value)
What’s special about this value? Why doesn’t Visual Studio use Value.GetHashCode()
directly? As I understand, it doesn’t really affect hash distribution. Since it’s just addition, consecutive values would still accumulate together.
EDIT: I only tried this with different classes with Value
properties but apparently property name affects the number generated. For instance, if you rename the property to Halue
, the number becomes 387336856.
#c-sharp #visual-studio #vscode
1588575551
If you look for -1521134295
in Microsoft’s repositories you’ll see that it appears quite a number of times
Most of the search results are in the GetHashCode
functions, but they all have the following form
int hashCode = SOME_CONSTANT;
hashCode = hashCode * -1521134295 + field1.GetHashCode();
hashCode = hashCode * -1521134295 + field2.GetHashCode();
// ...
return hashCode;
The first hashCode * -1521134295 = SOME_CONSTANT * -1521134295
will be pre-multiplied during the generation time by the generator or during compilation time by CSC. That’s the reason for -1937169414
in your code
Digging deeper into the results reveals the code generation part which can be found in the function 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);
}
As you can see the hash depends on the symbol names. In that function the constant is also called permuteValue
, probably because after the multiplication the bits are permuted around somehow
// -1521134295
var permuteValue = CreateLiteralExpression(factory, hashFactor);
There are some patterns if we view the value in binary: 101001 010101010101010 101001 01001
or 10100 1010101010101010 10100 10100 1
. But if we multiply an arbitrary value with that then there are lots of overlapping carries so I couldn’t see how it works. The output may also has different number of set bits so it’s not really a permutation
You can find the another generator in Roslyn’s AnonymousTypeGetHashCodeMethodSymbol which calls the constant 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)
The real reason for choosing that value is yet still unclear
1588575300
If you use Visual Studio’s own refactoring menu to add a GetHashCode implementation to a class like this:
and select the only int property in the class:
it generates this code on .NET Framework:
public override int GetHashCode()
{
return -1937169414 + Value.GetHashCode();
}
(it generates HashCode.Combine(Value)
on .NET Core instead, which I’m not sure if it involves the same value)
What’s special about this value? Why doesn’t Visual Studio use Value.GetHashCode()
directly? As I understand, it doesn’t really affect hash distribution. Since it’s just addition, consecutive values would still accumulate together.
EDIT: I only tried this with different classes with Value
properties but apparently property name affects the number generated. For instance, if you rename the property to Halue
, the number becomes 387336856.
#c-sharp #visual-studio #vscode