我的 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() 是否更合理?
更新:我刚刚在 Bill Wagner 的好书Effective C#中再次查看了这个主题,他在“第 10 项:理解 GetHashCode() 的陷阱”中指出:
如果您定义的类型永远不会用作容器中的键,那么这无关紧要。表示窗口控件、网页控件或数据库连接的类型不太可能用作集合中的键。在这些情况下,什么也不做。所有引用类型都会有一个正确的哈希码,即使它非常低效。[...] 在您创建的大多数类型中,最好的方法是完全避免 GetHashCode() 的存在。
...这就是我最初得到这个想法的地方,即我不必总是关心 GetHashCode()。