【问题标题】:If getHashCode() for string or integer is not guaranteed to be unique why use it?如果字符串或整数的 getHashCode() 不能保证是唯一的,为什么要使用它?
【发布时间】:2019-12-07 12:33:48
【问题描述】:

正如我在标题中所写。

如果在您的应用程序中使用 getHashCode() 不安全,为什么要使用它? (对于字符串和整数) 我想用它来交叉方法,除了 Linq 模型中的方法 或创建我自己的 IEqualityCompare 类。 感觉像是一个机会——如果不是 100% 安全?

还是我错过了什么?

正如https://docs.microsoft.com/中的String.GetHashCode方法所引用的那样

重要

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

不保证哈希码本身是稳定的。对于单个 .NET 版本,相同字符串的哈希码在 .NET 实现、.NET 版本以及 .NET 平台(例如 32 位和 64 位)之间可能会有所不同。在某些情况下,它们甚至可能因应用程序域而异。这意味着同一程序的两次后续运行可能会返回不同的哈希码。

因此,哈希码绝不能在它们所在的应用程序域之外使用 创建时,它们不应该被用作集合中的关键字段,也不应该被持久化。

最后,如果出现以下情况,请不要使用哈希码代替加密哈希函数返回的值 你需要一个加密的强哈希。对于加密哈希,使用从 System.Security.Cryptography.HashAlgorithm 或 System.Security.Cryptography.KeyedHashAlgorithm 类。

有关哈希码的详细信息,请参阅 Object.GetHashCode。

【问题讨论】:

  • 来自GetHashCode 的哈希不是安全哈希,但您可能不需要ExceptIntersect 的安全哈希。
  • 我猜关键是“两个后续运行”,我从未观察到同一 AppDomain 中的两个 string.GetHashCode 调用都返回了两个不同的 HashCode。我最近尝试使用 GetHashCode 来评估我的序列化对象图和反序列化对象图是否基于其值 GetHashCode 相同,因为它们与我重新启动应用程序时不同。只有在我的单元测试中,它们与调用序列化和反序列化的过程相同。
  • GetHashCode 不是为了安全。唯一的目的是生成索引。您引用的文档明确指出使用GetHashCode 进行安全哈希,而是使用System.Security.Cryptography 命名空间中的类。
  • 你从不使用 only GetHashCode(),接下来你使用 Equals() 来测试相等性。关键是哈希可以显着减少你必须做的相等测试的数量。 this Q+A 很好地证明了这如何产生代码的主要加速。
  • 如果我没记错的话,.net 框架中的底层 GetHashCode 实现是将指针值考虑在内,对于原始值,它在字符串表中的位置(忘记了如何调用表)

标签: c# linq hashcode iequalitycomparer


【解决方案1】:

我认为让你感到困惑的是你认为,哈希码映射到一个值的地址,但它并不完全一样。

把它想象成书架,哈希码映射到书架的地址。如果其中两个具有相同的 HashCode 将被放置在同一个书架中,并且有一个书架的地址,其中有 3 本书,字典只检查书架上的三本书,而不是所有的书。因此,唯一的哈希码越多,字典查找就越快。

当您创建IEqualityComparer 时,如果您可以使GetHashCode() 返回唯一值,那么使用它的 Dictionary 或 HashSet 将比存在许多重复项时执行得更快。

检查这个例子:

public int GetShashCode(string ojb)
{
     return obj.Length;
}

虽然它比遍历整个字符串要快得多,但它不是很独特(虽然它是有效的)

这个例子也是有效的,但更糟糕的选择:

public int GetShashCode(string ojb)
{
     return (int)obj[0];
}

根据你可以猜到的字符串的内容,你可以做出更好的哈希码(例如你知道它是一个社会安全号码,格式如下:“XXX-XX-XXXX”,其中每个 X 代表一个digit) 将是一个不错的选择:

public int GetShashCode(string ojb)
{
     return int.Parse(obj.Replace("-",""));
}

【讨论】:

    【解决方案2】:

    如果在您的应用程序中使用 getHashCode() 不安全,为什么要使用它?

    GetHashCode 有不同的用途。如果您需要对字符串进行相等性测试,您可能应该使用 String.Equals== 运算符,它们可以保证正常工作。

    哈希码并不是为每个可能的字符串生成唯一编号的方法,这是不可能的。这是hash function的定义:

    哈希函数是可用于将任意大小的数据映射到固定大小值的任何函数。

    它只是将几乎无限的字符串集合映射到(相对)非常有限的整数集合。如果您需要将大量字符串均匀地分布到较小的“桶”中,您可能需要使用哈希码。哈希码广泛用于基于哈希的集合中,例如HashSet

    GetHashCode 的文档提到了这种方法的不同问题:

    • 该方法可以在不同的域/机器/.Net 版本上为相同的字符串生成不同的结果。这意味着将哈希作为某种唯一标识符在外部存储以供以后使用不是一个好主意;
    • 结果的密码强度不高,因此如果您需要牢不可破的密码盐,则不应使用它。

    当然,它看起来很吓人,但是,GetHashCode 对于内存中的集合来说已经足够好了,例如HashSetDictionary

    另外,请参阅这个问题:Why is it important to override GetHashCode when Equals method is overridden?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-09-01
      • 1970-01-01
      • 2016-01-17
      • 2023-04-01
      • 2012-09-10
      • 2011-04-07
      • 1970-01-01
      • 2022-12-10
      相关资源
      最近更新 更多