Object.GetHashCode()对引用或值是唯一的吗?

Object.GetHashCode()上的MSDN文档描述了该方法应该如何工作的3条矛盾规则。

  1. 如果两个相同类型的对象表示相同的值,则哈希函数必须为任一对象返回相同的常量值。
  2. 为获得最佳性能,哈希函数必须为所有输入生成随机分布。
  3. 无论对对象做出任何更改,哈希函数都必须返回完全相同的值。

规则1和3与我相矛盾。

Object.GetHashCode()是否根据对象的或对象的引用返回唯一编号。 如果我覆盖该方法,我可以选择使用什么,但我想知道如果有人知道,内部使用的是什么。

规则1和3与我相矛盾。

在某种程度上,他们是。 原因很简单:如果对象存储在哈希表中,并且通过更改其值,您更改其哈希值,则哈希表已丢失该值,您无法通过查询哈希表再次找到它。 重要的是,当对象存储在哈希表中时,它们保留其哈希值。

要实现这一点,通常最简单的方法是使可清洗对象不可变,从而避免整个问题。 然而,仅使那些确定散列值的字段不可变是足够的。

请考虑以下示例:

struct Person { public readonly string FirstName; public readonly string Name; public readonly DateTime Birthday; public int ShoeSize; } 

人们很少改变他们的生日,大多数人都不会改变他们的名字(除非结婚)。 然而,他们的鞋子尺寸可能会任意增长,甚至会缩小。 因此,使用他们的生日和名字而不是他们的鞋子大小识别人是合理的。 哈希值应该反映这一点:

 public int GetHashCode() { return FirstName.GetHashCode() ^ Name.GetHashCode() ^ Birthday.GetHashCode(); } 

不确定您指的是什么MSDN文档。 查看Object.GetHashCode( http://msdn.microsoft.com/en-us/library/system.object.gethashcode.aspx )上的当前文档提供了以下“规则”:

  • 如果两个对象比较相等,则每个对象的GetHashCode方法必须返回相同的值。 但是,如果两个对象的比较不相等,则两个对象的GetHashCode方法不必返回不同的值。

  • 只要没有对对象状态的修改来确定对象的Equals方法的返回值,对象的GetHashCode方法必须始终返回相同的哈希代码。 请注意,这仅适用于当前应用程序的执行,并且如果再次运行应用程序,则可以返回不同的哈希代码。

  • 为获得最佳性能,哈希函数必须为所有输入生成随机分布。

如果您指的是第二个项目符号点,则此处的关键短语是“只要没有对对象状态的修改”和“仅对应用程序的当前执行为真”。

另外从文档中,

哈希函数用于快速生成对应于对象的数字(哈希码)。 散列函数通常特定于每个类型,并且必须至少使用一个实例字段作为输入。 [ 重点补充是我的。 ]

至于实际实现,它明确指出派生类可以推迟到Object.GetHashCode实现, 当且仅当该派生类将值相等定义为引用相等且类型不是值类型时。 换句话说,Object.GetHashCode的默认实现将基于引用相等性,因为不存在要使用的实例字段,因此不保证不同对象的唯一返回值。 否则,您的实现应该特定于您的类型,并且应该至少使用一个实例字段。 例如,String.GetHashCode的实现为相同的字符串值返回相同的哈希码,因此如果两个String对象表示相同的字符串值,则返回相同的哈希码,并使用字符串中的所有字符生成该哈希值。

规则1和3并非真正矛盾。

对于引用类型,哈希代码是从对象的引用派生的 – 更改对象的属性,引用是相同的。

对于值类型,哈希代码是从值派生的,更改值类型的属性,并获得值类型的全新实例。

Eric Lipperts(C#的设计者)博客中提供了关于如何处理GetHashCode (超出Microsoft规则)的非常好的解释,其中包含文章“ GetHashCode的指南和规则 ”。 在这里添加超链接是不好的做法(因为它们可能无效),但这个是值得的,如果上面的信息,如果超链接丢失,可能仍会找到它。

默认情况下,它基于对象的引用来完成它,但这意味着它是完全相同的对象,因此两者都将返回相同的哈希。 但是散列应该基于该值,就像字符串类一样。 “a”和“b”将具有不同的散列,但“a”和“a”将返回相同的散列。

我无法确定Object.GetHashCode是如何在真正的 .NET Framework中实现的,但在Rotor中它将对象的SyncBlock索引用作哈希码。 网上有一些关于它的博客文章,但大多数是2005年。