4

我想根据要搜索的对象和一些搜索设置缓存一些搜索结果。

但是:这会创建一个相当长的缓存键,我想我会为它创建一个快捷方式,我想我会使用GetHashCode()它。

所以我想知道,GetHashCode()总是会产生不同的数字,即使我有很长的字符串或仅以此不同:'ä'而不是'a'

我尝试了一些字符串,似乎答案是肯定的,但不理解这种GetHashCode()行为并不能让我真正感觉到我是对的。

而且因为它是当你没有准备好时会弹出的那些东西之一(客户端正在查看错误搜索的缓存结果)我想确定......

编辑:如果 MD5 可以工作,我当然可以更改我的代码不使用 GetHashCode,目标是获得比原始字符串更短的字符串(> 1000 个字符)

4

5 回答 5

9

你不能指望GetHashCode()自己是独一无二的。

在http://kennetthorman.blogspot.com/2010/09/c-net-equals-and-getashcode.html上有一篇很好的文章调查了冲突的可能性。调查结果是“对不同字符串返回相同哈希码的调用 GetHashCode() 的最少次数是在 565 次迭代之后,而在发生哈希码冲突之前的最高迭代次数是 296390 次迭代。”

为了让您能够理解实施合同GetHashCode,以下是 MSDN 文档的摘录Object.GetHashCode()

哈希函数必须具有以下属性:

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

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

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

GetHashCodeC# 编译器团队的 Eric Lippert在他的博客http://ericlippert.com/2011/02/28/guidelines-and-rules-for-getashcode/上解释了实现规则的基本原理。

于 2012-09-11T09:40:13.750 回答
8

逻辑上GetHashCode 不可能是唯一的,因为只有 2^32 个整数和无限数量的字符串(参见鸽洞原理)。


正如@Henk在评论中指出的那样,即使有无限数量的字符串,也有有限数量的System.Strings。不过鸽子洞原理仍然比后者大得多int.MaxValue

于 2012-09-11T09:42:59.717 回答
2

如果将每个字符串的哈希码与字符串本身一起存储,则可以将字符串的哈希码作为“第一步”来比较它们是否相等。如果两个字符串具有不同的哈希码,它们就不相等,并且不必费心做任何其他事情。如果希望比较多对长度相同且“几乎”但不完全相等的字符串,则在检查内容之前检查哈希码可能是一种有用的性能优化。 请注意,如果没有缓存哈希码,这种“优化”将不值得,因为计算两个字符串的哈希码几乎肯定会比比较它们慢. 但是,如果必须出于其他目的计算和缓存哈希码,则将检查哈希码作为比较字符串的第一步可能会很有用。

于 2013-01-07T20:57:45.930 回答
1

使用 GetHashCode() 时总是有冲突的风险,因为您在有限的数字空间 Int32 内操作,而且散列算法无法在该空间内完美分布的事实也会加剧这种情况。

如果您查看 HashTable 或 Dictionary 的实现,您会看到 GetHashCode 用于将键分配到桶中以减少所需的比较次数,但是,如果同一桶中有多个项目,则仍然需要相等比较。

于 2012-09-11T09:43:31.517 回答
0

不,GetHasCode 只提供一个哈希码。会有碰撞。具有不同的散列意味着字符串是不同的,但具有相同的散列并不意味着字符串是相同的。

阅读Eric Lippert 的这些指导方针以正确使用 GetHashCode,它们很有指导意义。

如果你想比较字符串,就这样做!stringA == stringB工作正常。如果你想确保一个字符串在一个大集合中是唯一的,使用哈希码的力量来做到这一点,使用HashSet<string>.

于 2012-09-11T09:42:47.117 回答