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

时间:2015-11-16 23:03:09

标签: c# .net string hash

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

public virtual int GetHashCode(); // Defined in System.Object

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

  

鉴于String类已经具有使用字符数据的实体哈希码算法   用于计算哈希值的字符串,如果您可以在类上标识一个对于所有实例(例如社会保险号)应该是唯一的字段数据,则只需在该点上调用GetHashCode()   现场数据。

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

public string SSN {get; }

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

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

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

  

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

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

谢谢!

3 个答案:

答案 0 :(得分:5)

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

你认为这句话的含义是错误的。

此引用特别针对实现包含Person属性的SSN类的哈希码计算的上下文。等于SSN值表示相等的Person值。不同的SSN值表示不同的Person值。 (注意:实际上这不一定是真的。)

现在,您需要对Person进行哈希码计算,以确保两个相等的Person实例具有相同的哈希码,理想情况下,这可能导致两个不等Person个实例一个不同的哈希码,虽然后者永远无法保证。由于相等性是根据SSN定义的,这意味着重新使用SSN的哈希码已经实现了这一点。

答案 1 :(得分:5)

  

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

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

  

不要用作唯一标识符

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

看看Eric Lippert的blog on the topic

答案 2 :(得分:3)

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

哈希函数必需以确保x == y,然后x.GetHashCode() == y.GetHashCode(),但反之为为真:两个不同的对象可以具有相同的哈希码。这种情况称为哈希冲突

如果存在冲突,哈希表结构仍将工作,但它们运行速度较慢,因为您的程序必须花时间消除 冲突对象的哪个寻找。因此,良好的哈希函数将努力减少冲突。 (注意,由于pigeonhole principle,如果一个类有超过2个 32 可能的值,那么完全避免冲突的数学上是不可能的。 )

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

据Troelsen说,没有。只需使用“最独特”的string字段,然后点击GetHashCode()即可。编写System.String.GetHashCode的开发人员知道他们在做什么,所以只需使用它,您就会自动利用他们的“实体哈希码算法”。