繁体   English   中英

覆盖C#中的Object.Equals()实例方法;现在代码分析/ FxCop警告CA2218:“还应该重新定义GetHashCode”。我该抑制吗?

[英]Overriding Object.Equals() instance method in C#; now Code Analysis/FxCop warning CA2218: “should also redefine GetHashCode”. Should I suppress this?

我在C#项目中有一个复杂的类,我希望能够进行相等测试。 这不是一个微不足道的阶级; 它包含各种标量属性以及对其他对象和集合的引用(例如IDictionary)。 为了它的价值,我的班级是密封的。

为了在我的系统中的其他地方启用性能优化(避免昂贵的网络往返的优化),我需要能够将这些对象的实例相互比较以实现相等 - 除了内置的引用相等 - 所以我重写了Object.Equals()实例方法。 但是,现在我已经这样做了,Visual Studio 2008的代码分析又称FxCop,我默认启用它,它引发了以下警告:

警告:CA2218:Microsoft.Usage:由于'MySuperDuperClass'重新定义了Equals,它还应该重新定义GetHashCode。

我想我理解这个警告的基本原理: 如果我要将这些对象用作集合中的 ,那么哈希码很重要。 看到这个问题 但是,我不打算将这些对象用作集合中的键。 永远。

感觉有理由压制警告,我在MSDN文档中查找了代码CA2218以获取警告的全名,因此我可以将SuppressMessage属性应用于我的类,如下所示:

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

但是,在进一步阅读时,我注意到以下内容:

如何修复违规行为

要修复违反此规则的行为,请提供GetHashCode的实现。 对于一对相同类型的对象,如果Equals的实现为该对返回true,则必须确保实现返回相同的值。

何时抑制警告

-----> 不要压制此规则的警告。 [箭头和重点我的]

所以,我想知道: 为什么我不应该按照我的计划来压制这个警告? 我的情况不是要求抑制吗? 我不想为这个永远不会被调用的对象编写GetHashCode()的实现,因为我的对象永远不会成为集合中的键。 如果我想要迂腐而不是抑制,那么用一个抛出NotImplementedException的实现覆盖GetHashCode()会更合理吗?


更新:我只是在比尔瓦格纳的好书“ 有效C#”中重新审视了这个主题,他在“第10项:了解GetHashCode()的陷阱”中说:

如果您定义的类型不会被用作容器中的键,那么这无关紧要。 表示窗口控件,网页控件或数据库连接的类型不太可能用作集合中的键。 在那些情况下,什么都不做。 即使效率非常低,所有引用类型都将具有正确的哈希码。 [...]在您创建的大多数类型中,最好的方法是完全避免GetHashCode()的存在。

...这就是我最初得到这个想法,我不必总是关注GetHashCode()。

如果你是reallio-trulio absosmurfly 肯定你永远不会使用这个东西作为哈希表的关键,那么你的提议是合理的。 覆盖GetHashCode; 让它抛出一个例外。

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

或者,如果你不想那么苛刻: 覆盖GetHashCode; 使它总是返回零。 这符合GetHashCode的语义要求; 两个相等的对象总是具有相同的哈希码。 如果它曾经被用作字典中的关键字,那么性能会很糟糕,但是当它出现时你可以处理它,你声称它永远不会。

所有这一切:来吧。 您可能花了更多时间来输入问题,而不是正确实现它。 去做就对了。

你不应该压制它。 看看你的equals方法是如何实现的。 我确信它比较了班上的一个或多个成员来确定平等。 其中一个成员通常足以区分一个对象,因此您可以通过返回membername.GetHashCode();来实现GetHashCode membername.GetHashCode();

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

就像你说你永远不会需要它一样,你可能会改变主意,或者其他人可能对如何使用代码有其他想法。 工作GetHashCode并不难,并保证将来不会出现任何问题。

一旦你忘记了,或者另一个不知道的开发人员使用了这个,有人会有一个痛苦的错误来追查。 我建议只是正确实现GetHashCode,然后你就不用担心了。 或者只是不要将Equals用于特殊的相等比较案例。

GetHashCodeEquals方法协同工作,为您的类型提供基于值的相等语义 - 您应该一起实现它们。

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM