C# - String.GetHashCode() - >不要用作唯一标识符

jen*_*nsa 1 .net c# string hash

我目前正在阅读Troelsen的书籍C#和.NET 4.5框架.书中有一节他有一个覆盖的例子

public virtual int GetHashCode(); // Defined in System.Object
Run Code Online (Sandbox Code Playgroud)

他说(以下引用来自Troelsen的书):

鉴于String类已经具有使用String的字符数据来计算哈希值的实体哈希码算法,如果您可以在类上识别对于所有实例应该是唯一的一段字段数据(例如社会安全号码,只需在该字段数据上调用GetHashCode().

基本上他说的是某个类有一个成员(自动只读属性)

public string SSN {get; }
Run Code Online (Sandbox Code Playgroud)

并且该类的每个实例都将具有唯一的字符串值.现在,在假设

// s1 and s2 are strings
s1.GetHashCode() != s2.GetHashCode(); // Assumption: If this true then s1 == s2 is true
Run Code Online (Sandbox Code Playgroud)

他的推理是有效的.但是,当我读到String.GetHashCode()时:

如果两个字符串对象相等,则GetHashCode方法返回相同的值.但是,每个唯一字符串值都没有唯一的哈希码值.不同的字符串可以返回相同的哈希码.

我想你知道我要去哪里.我想是我错过了什么,如果有的话,请指出我正确的方向.

谢谢!

dan*_*n04 6

的目的GetHashCode不是为对象生成唯一标识符,而是实现基于哈希表的数据结构,例如Dictionary<K, V>HashSet<T>

是哈希函数要求,以确保如果x == y,然后x.GetHashCode() == y.GetHashCode(),但反之成立:两个不同的对象可以有相同的散列码。这种情况称为散列冲突

哈希表的结构仍然会正常工作,如果有冲突,但运行速度较慢,因为你的程序有花时间disambiguiting你要搜索的碰撞对象。因此,一个好的散列函数将努力最小化冲突。(请注意,由于鸽巢原理,如果一个类的可能值超过 2 32 个,则完全避免碰撞在数学上是不可能的。)

那么,你如何GetHashCode为你的类编写一个好的实现呢?做一些复杂的数学运算将您班级的每个字段转换为int,然后对其进行分析以确定其中系数的最佳值?

根据特罗尔森的说法,没有。只需选择您“最独特”的string领域并调用GetHashCode()它。编写代码的开发人员System.String.GetHashCode知道他们在做什么,所以只要使用它,你就会自动利用他们的“可靠的哈希码算法”。


小智 5

你是对的,相等的哈希码不能保证相等的值.

你错误地认为这句话的意思不然.

该引用特别是在为Person包含SSN属性的类实现哈希码计算的上下文中.等值SSN意味着相等的Person值.不同的SSN值意味着不同的Person值.(注意:实际上这不一定是真的.)

现在,您需要一个哈希码计算,Person以确保两个相等的Person实例具有相同的哈希码,并且理想情况下,这使得两个不相等的Person实例可能具有不同的哈希码,尽管后者永远无法保证.由于相等是根据SSN定义的,这意味着重新使用SSN的哈希码已经实现了.


Eri*_* J. 5

如果两个字符串对象相等,则GetHashCode方法返回相同的值.但是,每个唯一字符串值都没有唯一的哈希码值.不同的字符串可以返回相同的哈希码.

有无限数量的字符串,但只有2 ^ 32个可能的哈希码值.两个不同的字符串最终将具有相同的散列值是不可避免的.由于生日问题,这种情况比人们想象的更频繁.

不要用作唯一标识符

这是个好建议..NET的调试版本实际上会定期更改哈希代码以帮助捕获此类问题,并且不同的框架版本无法保证生成相同的哈希.欲了解更多请参阅本.

看看Eric Lippert 关于这个主题博客.