【问题标题】:C# .NET GetHashCode function questionC# .NET GetHashCode 函数问题
【发布时间】:2011-11-10 16:11:06
【问题描述】:

您好,我有一个包含 6 个字符串属性的类。一个唯一的对象将在这些字段中的至少一个具有不同的值

为了实现 IEqualityComparer 的 GetHashCode 函数,我将所有 6 个属性连接起来并在结果字符串上调用 GetHashCode。

我有以下疑惑:

  1. 是否需要对唯一值调用 GetHashcode?​​li>
  2. 六个属性的串联操作会不会导致比较慢?
  3. 我应该使用其他方法吗?

【问题讨论】:

  • 您是否打算在某处比较您的对象,例如将它们排序为数组或类似的?这将改变您是否需要实现 GetHashCode
  • 嗨 mydogisbox,我将它用于 List.Contains 方法并将比较器对象传递给它。我已经实现了 Equals,但不知道 GetHashcode 的正确方法

标签: c# .net class gethashcode


【解决方案1】:

如果您的字符串字段被命名为 a-f 并且已知不为空,这是 ReSharper 为您的 GetHashCode() 提出的建议

public override int GetHashCode() {
  unchecked {
    int result=a.GetHashCode();
    result=(result*397)^b.GetHashCode();
    result=(result*397)^c.GetHashCode();
    result=(result*397)^d.GetHashCode();
    result=(result*397)^e.GetHashCode();
    result=(result*397)^f.GetHashCode();
    return result;
  }
}

【讨论】:

    【解决方案2】:

    GetHashCode 不需要为“不相等”的对象返回不相等的值。它只需要为相等的对象返回相等的值(它还必须在对象的生命周期内返回相同的值)。

    这意味着:

    1. 如果两个对象与Equals 比较相等,则它们的GetHashCode 必须返回相同的值。
    2. 如果 6 个字符串属性中的某些不是严格只读的,则它们无法参与 GetHashCode 实现。

    如果您不能同时满足这两点,您应该重新评估您的设计,因为其他任何事情都会为错误敞开大门。

    最后,您可以通过对 6 个字符串中的每一个调用 GetHashCode,然后使用一些按位运算将所有 6 个结果整合为一个值来使 GetHashCode 更快。

    【讨论】:

    • 嗨 Jon,我的所有属性都不是只读的。但是,它们都有私有设置器,但只能从构造函数中修改。这会影响它们在 GetHashCode 中的使用吗?
    • @ganeshran:那么它们在对象的生命周期内实际上是只读的(即,如果您愿意,它们可以使用readonly 支持字段来实现),这就足够了。你会没事的。
    • @Jon 阅读了GetHashCode() 实施的条件,我发现这是一个需求冲突的问题。事实上,你只说对了一部分。 GetHashCode() 方法的真正要求是: 1. 它应该为相等的对象返回相同的值。 2. 它应该为同一个对象返回相同的值,而它没有被修改。 3. GetHashCode() 应该很快。同意,还有其他一些建议。例如这个:为了获得最佳性能,哈希函数应该为所有输入生成随机分布。
    • 这句话回答了我“GetHashCode不需要为“不相等”的对象返回不相等的值。它只需要为相等的对象返回相等的值(它也必须在生命周期内返回相同的值对象)。”一开始我错过了。
    • @ganeshran:请注意,希望为不相等的对象返回不相等的值;它只是不是必需的(实际上,它不可能在数学上实现)。 return 42; 是技术意义上的“正确”实现,但如果将这些对象放入字典中,则会降低性能。
    【解决方案3】:

    如果您对这些对象调用 Equals(),GetHashCode() 应该为所有返回 true 的对象返回相同的哈希码。这意味着,例如,无论字段值是什么,您都可以返回零作为哈希码。但这会使您的对象在存储在诸如哈希表之类的数据结构中时非常低效。

    组合字符串是一种选择,但请注意,例如,您可以只组合两个字符串作为哈希码(同时仍然比较所有字符串等于!)。

    您还可以组合六个单独字符串的哈希值,而不是为组合字符串计算单个哈希值。参见例如 Quick and Simple Hash Code Combinations

    我不确定这是否会比连接字符串快得多。

    【讨论】:

    • 谢谢安德斯,我只用它来比较包含方法。如果我只组合哈希码的两个字符串,如果对象中的两个值相同,哈希码会不会相同?这会搞乱比较,还是 GetHashCode 对比较本身没有影响,只会影响性能
    • 其他人已经提出了这一点,但我想以不同的方式解决它,因为您的直觉似乎被卡住了。观察 GetHashCode() 返回一个 int,它只能接受 2^32 个不同的值。您的对象包含 6 个任意长度的字符串,显然可以采用大量值。通过这个例子,我们可以很容易地看到 GetHashCode() 不可能是对象所有可能值的唯一值。它必须只满足这个属性:“if a.Equals(b) then a.GetHashCode()==b.GetHashCode()”;并注意“如果”不是双向的。
    • GetHashCode() 的实际考虑是它“好”和“快”。为了让它“快”,我会尽量避免所有的内存分配和字符串复制;使它“好”是一些细微差别的主题,但实际上就像@Jon 建议的那样,将子对象的 GetHashCode() 值混合在一起就足够了。我会将 ReSharper 的建议作为“答案”发布,以便获取代码格式。
    • 谢谢科里,我现在明白了。抱歉,如果我的回答看起来很无聊——因为我没有真正了解 GetHashCode 的实际工作方式并用于比较。我现在明白了。
    【解决方案4】:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-03
      • 1970-01-01
      • 1970-01-01
      • 2012-09-26
      • 2023-03-22
      • 2011-10-24
      相关资源
      最近更新 更多