如果使用Visual Studio自己的重构菜单将GetHashCode实现添加到这样的类中,则:
并选择类中唯一的int属性:
它在.NET Framework上生成此代码:
public override int GetHashCode()
{
return -1937169414 + Value.GetHashCode();
}
(它代替在.NET Core上生成HashCode.Combine(Value)
,我不确定它是否包含相同的值)
此值有什么特别之处?为什么Visual Studio不直接使用Value.GetHashCode()
?据我了解,它并不会真正影响哈希分布。由于只是加法,所以连续的值仍会累积在一起。
编辑:我仅使用具有Value
属性的不同类尝试了此操作,但显然属性名称会影响生成的数字。例如,如果将属性重命名为Halue
,数字将变为387336856。感谢GökhanKurt指出了这一点。
Halue
,该数字将改为387336856。我曾尝试过使用不同的类,但没有考虑重命名该属性。Gökhan的评论使我明白了它的目的。它基于确定的但随机分布的偏移量来偏移哈希值。这样,即使使用简单的加法运算,将不同类的哈希值组合在一起,仍然可以稍微抵抗哈希冲突。
例如,如果您有两个具有相似的GetHashCode实现的类:
public class A
{
public int Value { get; set;}
public int GetHashCode() => Value;
}
public class B
{
public int Value { get; set;}
public override int GetHashCode() => Value;
}
并且如果您有另一个包含对这两个引用的类:
public class C { public A ValueA { get; set; } public B ValueB { get; set; } public override int GetHashCode() { return ValueA.GetHashCode() + ValueB.GetHashCode(); } }
这样的不良组合将易于出现哈希冲突,因为如果ValueA和ValueB的值彼此接近,则对于哈希值A和ValueB的不同值,生成的哈希码将在同一区域周围累积。如果您使用乘法或按位运算来组合它们,实际上并不重要,如果没有均匀间隔的偏移,它们仍然很容易发生冲突。由于编程中使用的许多整数值都在0附近累积,因此使用这样的偏移量是有意义的。显然,具有良好位模式的随机偏移是一种好习惯。
我仍然不确定为什么他们不使用完全随机的偏移量,可能不会破坏依赖于GetHashCode()确定性的任何代码,但是很高兴收到Visual Studio团队对此的评论。] >