为什么为匿名 class 生成的 GetHashCode() 实现中的初始哈希值取决于 属性 名称?
Why does initial hash value in GetHashCode() implementation generated for anonymous class depend on property names?
在为匿名 class 生成 GetHashCode()
实现时,Roslyn 根据 属性 名称计算初始哈希值。例如,为
生成的 class
var x = new { Int = 42, Text = "42" };
将有以下 GetHashCode()
方法:
public override in GetHashCode()
{
int hash = 339055328;
hash = hash * -1521134295 + EqualityComparer<int>.Default.GetHashCode( Int );
hash = hash * -1521134295 + EqualityComparer<string>.Default.GetHashCode( Text );
return hash;
}
但如果我们更改 属性 名称,初始值会更改:
var x = new { Int2 = 42, Text2 = "42" };
public override in GetHashCode()
{
int hash = 605502342;
hash = hash * -1521134295 + EqualityComparer<int>.Default.GetHashCode( Int2 );
hash = hash * -1521134295 + EqualityComparer<string>.Default.GetHashCode( Text2 );
return hash;
}
这种行为背后的原因是什么?选择一个大的 [prime?] 号码并将其用于所有匿名 classes 是否有问题?
除非 Roslyn 团队有人挺身而出,否则我们只能推测。我也会这样做的。为每个匿名类型使用不同的种子似乎是一种在哈希码中具有更多随机性的有用方法。例如,它导致 new { a = 1 }.GetHashCode() != new { b = 1 }.GetHashCode()
为真。
我也想知道是否有任何坏种子导致哈希码计算失败。我不这么认为。即使是 0
种子也可以。
可以在 AnonymousTypeGetHashCodeMethodSymbol
中找到 Roslyn 源代码。初始散列码值基于匿名类型名称的散列。
Is there some problem with just picking a big [prime?] number and using it for all the anonymous classes?
这样做并没有错,只是往往会产生一个效率较低的值。
GetHashCode
实现的目标是 return 对于不相等的值产生不同的结果。这减少了在基于散列的集合(例如 Dictionary<TKey, TValue>
)中使用值时发生冲突的机会。
如果匿名值代表不同的类型,则它们永远不能等于另一个匿名值。匿名值的类型由属性的形状定义:
- 属性名称
- 属性类型
- 属性数
两个在任何这些特征上不同的匿名值代表不同的类型,因此永远不可能是相等的值。
鉴于这是真的,编译器生成 GetHashCode
实现倾向于 return 不同类型的不同值是有意义的。这就是 the compiler 在计算初始哈希值时包含 属性 名称的原因。
在为匿名 class 生成 GetHashCode()
实现时,Roslyn 根据 属性 名称计算初始哈希值。例如,为
var x = new { Int = 42, Text = "42" };
将有以下 GetHashCode()
方法:
public override in GetHashCode()
{
int hash = 339055328;
hash = hash * -1521134295 + EqualityComparer<int>.Default.GetHashCode( Int );
hash = hash * -1521134295 + EqualityComparer<string>.Default.GetHashCode( Text );
return hash;
}
但如果我们更改 属性 名称,初始值会更改:
var x = new { Int2 = 42, Text2 = "42" };
public override in GetHashCode()
{
int hash = 605502342;
hash = hash * -1521134295 + EqualityComparer<int>.Default.GetHashCode( Int2 );
hash = hash * -1521134295 + EqualityComparer<string>.Default.GetHashCode( Text2 );
return hash;
}
这种行为背后的原因是什么?选择一个大的 [prime?] 号码并将其用于所有匿名 classes 是否有问题?
除非 Roslyn 团队有人挺身而出,否则我们只能推测。我也会这样做的。为每个匿名类型使用不同的种子似乎是一种在哈希码中具有更多随机性的有用方法。例如,它导致 new { a = 1 }.GetHashCode() != new { b = 1 }.GetHashCode()
为真。
我也想知道是否有任何坏种子导致哈希码计算失败。我不这么认为。即使是 0
种子也可以。
可以在 AnonymousTypeGetHashCodeMethodSymbol
中找到 Roslyn 源代码。初始散列码值基于匿名类型名称的散列。
Is there some problem with just picking a big [prime?] number and using it for all the anonymous classes?
这样做并没有错,只是往往会产生一个效率较低的值。
GetHashCode
实现的目标是 return 对于不相等的值产生不同的结果。这减少了在基于散列的集合(例如 Dictionary<TKey, TValue>
)中使用值时发生冲突的机会。
如果匿名值代表不同的类型,则它们永远不能等于另一个匿名值。匿名值的类型由属性的形状定义:
- 属性名称
- 属性类型
- 属性数
两个在任何这些特征上不同的匿名值代表不同的类型,因此永远不可能是相等的值。
鉴于这是真的,编译器生成 GetHashCode
实现倾向于 return 不同类型的不同值是有意义的。这就是 the compiler 在计算初始哈希值时包含 属性 名称的原因。