14

大家好,我一直在阅读为 .NET 中的对象实现 GetHashCode() 覆盖的最佳方法,并且我遇到的大多数答案都涉及以某种方式将数字类型的成员中的数字组合在一起以提出一种方法。问题是,我有一个使用字母数字字符串作为键的对象,我想知道仅使用字符串作为键的对象的内部 ID 是否存在根本性错误,如下所示?


// Override GetHashCode() to return a permanent, unique identifier for
// this object.
static private int m_next_hash_id = 1;
private int m_hash_code = 0;
public override int GetHashCode() {
  if (this.m_hash_code == 0)
    this.m_hash_code = <type>.m_next_hash_id++;
  return this.m_hash_code;
}

有没有更好的方法来为使用字母数字字符串作为键的对象提供唯一的哈希码?(不,字母数字字符串的数字部分不是唯一的;其中一些字符串实际上根本没有数字。)任何想法都将不胜感激!

4

5 回答 5

22

您可以调用GetHashCode()您在对象中使用的非数字值。

private string m_foo;
public override int GetHashCode()
{
    return m_foo.GetHashCode();
}
于 2010-07-23T17:34:54.740 回答
21

这不是为对象生成散列的好模式。

理解 GetHashCode() 的目的很重要——它是一种生成对象标识属性的数字表示的方法。哈希码用于允许对象充当字典中的键,并且在某些情况下加速复杂类型之间的比较。

如果您只是生成一个随机值并将其称为哈希码,那么您就没有可重复性。具有相同键字段的另一个实例将具有不同的哈希码,并且会违反 HashSet、Dictionary 等类所期望的行为。

如果您的对象中已经有一个标识字符串成员,则只需返回其哈希码。

对于计划覆盖该方法的任何人来说, MSDN 上的实现者文档GetHashCode()都是必读的:

给实施者的注意事项

哈希函数用于快速生成与对象的值对应的数字(哈希码)。散列函数通常特定于每种类型,并且为了唯一性,必须使用至少一个实例字段作为输入。

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

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

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

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

例如,String 类提供的 GetHashCode 方法的实现为相同的字符串值返回相同的哈希码。因此,如果两个 String 对象表示相同的字符串值,则它们返回相同的哈希码。此外,该方法使用字符串中的所有字符来生成合理随机分布的输出,即使输入聚集在某些范围内(例如,许多用户的字符串可能只包含较低的 128 个 ASCII 字符,即使字符串可以包含 65,535 个 Unicode 字符中的任何一个)。

于 2010-07-23T17:38:41.033 回答
2

哈希码不必是唯一的。如果您的Equals实现是正确的,则可以为两个实例返回相同的哈希码。逻辑被破坏了m_next_hash_id,因为它允许两个对象具有不同的哈希码,即使它们比较相等。

MSDN 提供了一套关于如何实现EqualsGetHashCode. 这里的几个示例GetHashCode是根据对象字段的哈希码实现的

于 2010-07-23T17:37:59.770 回答
0

是的,更好的方法是使用您已经拥有的字符串的哈希码。如果字母数字字符串定义了您拥有的对象的身份,那么它的哈希码将非常适合您的对象的哈希码。

增加静态字段并将其用作哈希码的想法是一个糟糕的想法。哈希码应该在可能值的空间中均匀分布。除其他外,这确保了它在用作哈希表中的键时会表现良好。

于 2010-07-23T17:35:14.637 回答
0

我相信您通常希望GetHashCode()返回通过它的值而不是实例来标识对象的东西,如果我在这里理解这个想法,我认为您的方法将确保GetHashCode()在具有等效值的两个不同对象上返回不同的哈希值,因为它们'是不同的实例。

GetHashCode()旨在返回一个值,该值可让您比较两个对象的值,而不是它们的引用。

于 2010-07-23T17:36:14.703 回答