我的C#项目中有一个复杂的类,我希望能够进行相等的测试。这不是一个微不足道的阶级;它包含各种标量属性以及对其他对象和集合的引用(例如IDictionary)。为了它的价值,我的班级是密封的。
为了在我的系统中的其他地方启用性能优化(避免昂贵的网络往返的优化),我需要能够将这些对象的实例相互比较以实现相等 - 除了内置的引用相等 - 所以我重写了Object.Equals()实例方法。但是,现在我已经这样做了,Visual Studio 2008的代码分析a.k.a. FxCop,我默认启用,它会引发以下警告:
警告:CA2218:Microsoft.Usage:自'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.")]
然而,在进一步阅读时,我注意到以下内容:
如何修复违规行为
要修复违反此规则的行为, 提供实施 GetHashCode的。对于一对物体 相同的类型,你必须确保 实现返回相同 如果你的Equals实现的价值 对该对返回true。
何时停止警告
- - - - > 不要压制此警告 规则。 [arrow&强调我的]
所以,我想知道:为什么我不应该按照我的计划来抑制这个警告?我的情况不能抑制吗?我不想为这个永远不会被调用的对象编写GetHashCode()的实现,因为我的对象永远不会成为集合中的键。如果我想要迂腐而不是抑制,那么用一个抛出NotImplementedException的实现覆盖GetHashCode()会更合理吗?
<小时/> 更新:我只是在Bill Wagner的好书Effective C#中再次看到这个主题,他在“第10项:了解GetHashCode()的陷阱”中说:
如果您要定义的类型不会 永远被用作一个关键 容器,这没关系。类型 代表窗口控件,web 页面控件或数据库连接 不太可能被用作a中的键 采集。在那些情况下,做 没有。所有参考类型都将 有一个正确的哈希码,甚至 如果效率很低。 [...]在... 你创造的大多数类型,最好的 方法是避免存在 GetHashCode()完全。
...这就是我最初得到这个想法的地方,我不需要一直关注GetHashCode()。
答案 0 :(得分:14)
如果你是reallio-trulio absosmurfly 肯定,你永远不会将这个东西用作哈希表的关键,那么你的提议是合理的。 覆盖GetHashCode;让它抛出异常。
请注意,哈希表隐藏在不太可能的地方。大量LINQ序列运算符在内部使用哈希表实现来加快速度。通过拒绝GetHashCode的实现,您也拒绝在各种LINQ查询中使用您的类型。我喜欢构建使用memoization来提高速度的算法; memoizers通常使用哈希表。因此,您也拒绝记住将类型作为参数的方法调用的能力。
或者,如果你不想那么苛刻:覆盖GetHashCode;使它始终返回零。符合GetHashCode的语义要求;两个相等的对象总是具有相同的哈希码。如果它曾经被用作字典中的键,那么性能会很糟糕,但是当它出现时你可以处理它,你声称它永远不会。
所有这一切:来吧。您可能花了更多时间来输入问题,而不是正确实现它。就这么做。
答案 1 :(得分:6)
你不应该压制它。看看你的equals方法是如何实现的。我确信它比较了班上的一个或多个成员来确定平等。其中一个成员通常足以将一个对象与另一个对象区分开来,因此您可以通过返回GetHashCode
来实现membername.GetHashCode();
。
答案 2 :(得分:5)
我的0.10美元价值?实现GetHashCode。
就像你说你永远不会需要它一样,你可能会改变主意,或者其他人可能对如何使用代码有其他想法。工作GetHashCode并不难,并保证将来不会出现任何问题。
答案 3 :(得分:5)
一旦你忘记了,或者另一个不知道的开发者使用了这个,有人会有一个痛苦的错误来追查。我建议只是正确实现GetHashCode,然后你就不用担心了。或者只是不要将Equals用于特殊的相等比较案例。
答案 4 :(得分:4)
GetHashCode
和Equals
方法共同为您的类型提供基于值的相等语义 - 您应该一起实现它们。
有关此主题的更多信息,请参阅以下文章:
无耻插件:这些文章是我写的。