代码之家  ›  专栏  ›  技术社区  ›  Chris W. Rea

重写c now code analysis/fxcop warning ca2218中的object.equals()实例方法:“还应重新定义gethashcode”。我应该抑制这个吗?

  •  5
  • Chris W. Rea  · 技术社区  · 16 年前

    在我的C项目中,我有一个复杂的类,在这个类上我希望能够进行平等测试。它不是一个普通的类;它包含各种标量属性以及对其他对象和集合(例如IDictionary)的引用。不管怎样,我的课是密封的。

    为了在我的系统中的其他地方实现性能优化(一种避免代价高昂的网络往返的优化),我需要能够将这些对象的实例相互比较以获得相等性(而不是内置的引用相等性),因此我将重写object.equals()inst。ance方法。但是,现在我已经完成了这项工作,Visual Studio 2008的代码分析a.k.a.fxcop(默认情况下保持启用状态)将引发以下警告:

    警告:CA2218:Microsoft。用法:自'mysuperduperclass'起 重新定义Equals,它还应重新定义GetHashCode。

    我想我理解这个警告的理由: 如果 我将使用 钥匙 在集合中,哈希代码很重要。即 see this question . 但是,我不会将这些对象用作集合中的键。曾经。

    我觉得有理由压制警告,于是抬起头来 code CA2218 in the MSDN documentation 获取警告的全名,以便应用 SuppressMessage 我的类的属性如下:

        [SuppressMessage("Microsoft.Naming",
            "CA2218:OverrideGetHashCodeOnOverridingEquals",
            Justification="This class is not to be used as key in a hashtable.")]
    

    然而,在进一步阅读时,我注意到以下几点:

    如何修复违规行为

    要纠正违反此规则的行为, 提供 获取哈希代码。对于一对 同一类型,必须确保 实现返回相同的 如果实现等于 对返回true。

    何时禁止警告

    -----> 不要禁止来自此的警告 规则。 [箭头和强调我的]

    所以,我想知道: 我为什么不在计划的时候压制这个警告呢? 我的案子不需要镇压吗?我不想为此永远不会被调用的对象编写getHashCode()的实现代码,因为我的对象永远不会是集合中的键。如果我想变得迂腐,而不是抑制,那么用一个抛出NotImplementedException的实现重写getHashCode()是否更合理?


    更新: 我刚刚在比尔·瓦格纳的好书中又查到了这个问题。 Effective C# 他在“第10项:了解gethashcode()的陷阱”中指出:

    如果定义的类型 曾被用作 容器,这没关系。类型 代表窗口控件的Web 页面控件或数据库连接 不太可能用作 收藏。在这种情况下,一定要 没有什么。所有引用类型都将 具有正确的哈希代码,甚至 如果效率很低。[…]英寸 您创建的类型最多,最好 方法是避免 完全获取hashcode()。

    …这就是我最初的想法,我不需要总是关心getHashCode()。

    5 回复  |  直到 9 年前
        1
  •  6
  •   Klaus Byskov Pedersen    16 年前

    你不应该压制它。看看equals方法是如何实现的。我确信它会比较类中的一个或多个成员以确定相等性。这些成员中的一个常常足以区分一个对象和另一个对象,因此您可以实现 GetHashCode 通过返回 membername.GetHashCode(); .

        2
  •  14
  •   Eric Lippert    16 年前

    如果你真的是特鲁里奥·阿布索姆弗利 积极的 你永远不会用这个东西作为哈希表的键,那么你的建议是合理的。 重写GetHashCode;使其引发异常。

    请注意,哈希表隐藏在不太可能的地方。许多LINQ序列运算符在内部使用哈希表实现来加快速度。通过拒绝gethashcode的实现,您也拒绝在各种LINQ查询中使用您的类型。我喜欢构建使用memoization提高速度的算法;memoizer通常使用哈希表。因此,您还拒绝将类型作为参数的方法调用memoize的功能。

    或者,如果你不想那么严厉: 重写GetHashCode;使其始终返回零。 满足gethashcode的语义要求;两个相等的对象总是具有相同的哈希代码。如果它曾经被用作字典中的一个键,那么性能将是非常糟糕的,但是当它出现时,您可以处理这个问题,而您声称它永远不会处理这个问题。

    都说了:来吧。您可能花了比正确实现问题所需的时间更多的时间来键入问题。想做就做。

        3
  •  5
  •   Steven Sudit    16 年前

    我的价值0.10美元?实现GetHashCode。

    尽管你说你永远不会,永远不需要它,但你可能会改变主意,或者其他人可能对如何使用代码有其他想法。一个有效的gethashcode并不难制作,并且保证将来不会有任何问题。

        4
  •  5
  •   ermau    16 年前

    一旦你忘记了,或者另一个不知道的开发人员使用了这个,就会有人有一个痛苦的bug需要跟踪。我建议您简单地正确实现gethashcode,这样您就不用担心了。或者只是不要在特殊的平等比较案例中使用equals。

        5
  •  4
  •   Andrew Hare    16 年前

    这个 GetHashCode 和 Equals 方法一起为您的类型提供基于值的平等语义——您应该一起实现它们。

    有关此主题的更多信息,请参阅以下文章:

    无耻插:这些文章是我写的。