简体   繁体   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?

I've got a complex class in my C# project on which I want to be able to do equality tests. 我在C#项目中有一个复杂的类,我希望能够进行相等测试。 It is not a trivial class; 这不是一个微不足道的阶级; it contains a variety of scalar properties as well as references to other objects and collections (eg IDictionary). 它包含各种标量属性以及对其他对象和集合的引用(例如IDictionary)。 For what it's worth, my class is sealed. 为了它的价值,我的班级是密封的。

To enable a performance optimization elsewhere in my system (an optimization that avoids a costly network round-trip), I need to be able to compare instances of these objects to each other for equality – other than the built-in reference equality – and so I'm overriding the Object.Equals() instance method. 为了在我的系统中的其他地方启用性能优化(避免昂贵的网络往返的优化),我需要能够将这些对象的实例相互比较以实现相等 - 除了内置的引用相等 - 所以我重写了Object.Equals()实例方法。 However, now that I've done that, Visual Studio 2008's Code Analysis aka FxCop, which I keep enabled by default, is raising the following warning: 但是,现在我已经这样做了,Visual Studio 2008的代码分析又称FxCop,我默认启用它,它引发了以下警告:

warning : CA2218 : Microsoft.Usage : Since 'MySuperDuperClass' redefines Equals, it should also redefine GetHashCode. 警告:CA2218:Microsoft.Usage:由于'MySuperDuperClass'重新定义了Equals,它还应该重新定义GetHashCode。

I think I understand the rationale for this warning: If I am going to be using such objects as the key in a collection, the hash code is important. 我想我理解这个警告的基本原理: 如果我要将这些对象用作集合中的 ,那么哈希码很重要。 ie see this question . 看到这个问题 However, I am not going to be using these objects as the key in a collection. 但是,我不打算将这些对象用作集合中的键。 Ever. 永远。

Feeling justified to suppress the warning, I looked up code CA2218 in the MSDN documentation to get the full name of the warning so I could apply a SuppressMessage attribute to my class as follows: 感觉有理由压制警告,我在MSDN文档中查找了代码CA2218以获取警告的全名,因此我可以将SuppressMessage属性应用于我的类,如下所示:

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

However, while reading further, I noticed the following: 但是,在进一步阅读时,我注意到以下内容:

How to Fix Violations 如何修复违规行为

To fix a violation of this rule, provide an implementation of GetHashCode. 要修复违反此规则的行为,请提供GetHashCode的实现。 For a pair of objects of the same type, you must ensure that the implementation returns the same value if your implementation of Equals returns true for the pair. 对于一对相同类型的对象,如果Equals的实现为该对返回true,则必须确保实现返回相同的值。

When to Suppress Warnings 何时抑制警告

-----> Do not suppress a warning from this rule. -----> 不要压制此规则的警告。 [arrow & emphasis mine] [箭头和重点我的]

So, I'd like to know: Why shouldn't I suppress this warning as I was planning to? 所以,我想知道: 为什么我不应该按照我的计划来压制这个警告? Doesn't my case warrant suppression? 我的情况不是要求抑制吗? I don't want to code up an implementation of GetHashCode() for this object that will never get called, since my object will never be the key in a collection. 我不想为这个永远不会被调用的对象编写GetHashCode()的实现,因为我的对象永远不会成为集合中的键。 If I wanted to be pedantic, instead of suppressing, would it be more reasonable for me to override GetHashCode() with an implementation that throws a NotImplementedException? 如果我想要迂腐而不是抑制,那么用一个抛出NotImplementedException的实现覆盖GetHashCode()会更合理吗?


Update: I just looked this subject up again in Bill Wagner's good book Effective C# , and he states in "Item 10: Understand the Pitfalls of GetHashCode()": 更新:我只是在比尔瓦格纳的好书“ 有效C#”中重新审视了这个主题,他在“第10项:了解GetHashCode()的陷阱”中说:

If you're defining a type that won't ever be used as the key in a container, this won't matter. 如果您定义的类型不会被用作容器中的键,那么这无关紧要。 Types that represent window controls, web page controls, or database connections are unlikely to be used as keys in a collection. 表示窗口控件,网页控件或数据库连接的类型不太可能用作集合中的键。 In those cases, do nothing. 在那些情况下,什么都不做。 All reference types will have a hash code that is correct, even if it is very inefficient. 即使效率非常低,所有引用类型都将具有正确的哈希码。 [...] In most types that you create, the best approach is to avoid the existence of GetHashCode() entirely. [...]在您创建的大多数类型中,最好的方法是完全避免GetHashCode()的存在。

... that's where I originally got this idea that I need not be concerned about GetHashCode() always. ...这就是我最初得到这个想法,我不必总是关注GetHashCode()。

If you are reallio-trulio absosmurfly positive that you'll never use the thing as a key to a hash table then your proposal is reasonable. 如果你是reallio-trulio absosmurfly 肯定你永远不会使用这个东西作为哈希表的关键,那么你的提议是合理的。 Override GetHashCode; 覆盖GetHashCode; make it throw an exception. 让它抛出一个例外。

Note that hash tables hide in unlikely places. 请注意,哈希表隐藏在不太可能的地方。 Plenty of LINQ sequence operators use hash table implementations internally to speed things up. 大量LINQ序列运算符在内部使用哈希表实现来加快速度。 By rejecting the implementation of GetHashCode you are also rejecting being able to use your type in a variety of LINQ queries. 通过拒绝GetHashCode的实现,您也拒绝在各种LINQ查询中使用您的类型。 I like to build algorithms that use memoization for speed increases; 我喜欢构建使用memoization来提高速度的算法; memoizers usually use hash tables. memoizers通常使用哈希表。 You are therefore also rejecting ability to memoize method calls that take your type as a parameter. 因此,您也拒绝记住将类型作为参数的方法调用的能力。

Alternatively, if you don't want to be that harsh: Override GetHashCode; 或者,如果你不想那么苛刻: 覆盖GetHashCode; make it always return zero. 使它总是返回零。 That meets the semantic requirements of GetHashCode; 这符合GetHashCode的语义要求; that two equal objects always have the same hash code. 两个相等的对象总是具有相同的哈希码。 If it is ever used as a key in a dictionary performance is going to be terrible, but you can deal with that problem when it arises, which you claim it never will. 如果它曾经被用作字典中的关键字,那么性能会很糟糕,但是当它出现时你可以处理它,你声称它永远不会。

All that said: come on. 所有这一切:来吧。 You've probably spent more time typing up the question than it would take to correctly implement it. 您可能花了更多时间来输入问题,而不是正确实现它。 Just do it. 去做就对了。

You should not suppress it. 你不应该压制它。 Look at how your equals method is implemented. 看看你的equals方法是如何实现的。 I'm sure it compares one or more members on the class to determine equality. 我确信它比较了班上的一个或多个成员来确定平等。 One of these members is oftentimes enough to distinguish one object from another, and therefore you could implement GetHashCode by returning membername.GetHashCode(); 其中一个成员通常足以区分一个对象,因此您可以通过返回membername.GetHashCode();来实现GetHashCode membername.GetHashCode(); .

My $0.10 worth? 我的价值0.10美元? Implement GetHashCode. 实现GetHashCode。

As much as you say you'll never, ever need it, you may change your mind, or someone else may have other ideas on how to use the code. 就像你说你永远不会需要它一样,你可能会改变主意,或者其他人可能对如何使用代码有其他想法。 A working GetHashCode isn't hard to make, and guarantees that there won't be any problems in the future. 工作GetHashCode并不难,并保证将来不会出现任何问题。

As soon as you forget, or another developer who isn't aware uses this, someone is going to have a painful bug to track down. 一旦你忘记了,或者另一个不知道的开发人员使用了这个,有人会有一个痛苦的错误来追查。 I'd recommend simply implementing GetHashCode correctly and then you won't have to worry about it. 我建议只是正确实现GetHashCode,然后你就不用担心了。 Or just don't use Equals for your special equality comparison case. 或者只是不要将Equals用于特殊的相等比较案例。

The GetHashCode and Equals methods work together to provide value-based equality semantics for your type - you ought to implement them together. GetHashCodeEquals方法协同工作,为您的类型提供基于值的相等语义 - 您应该一起实现它们。

For more information on this topic please see these articles: 有关此主题的更多信息,请参阅以下文章:

Shameless plug: These articles were written by me. 无耻的插件:这些文章是我写的。

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

相关问题 有效的C#:覆盖Object.Equals(),不管是不是? - Effective C#: Overriding Object.Equals(), yay or nay? 为什么我收到此Resharper警告-不覆盖'Object.Equals(object o)和'Object.GetHashcode()' - Why I am getting this Resharper warning - does not override 'Object.Equals(object o) and 'Object.GetHashcode()' C#,在重写GetHashCode和Equals时应考虑哪些类字段/成员? - C#, Which class fields/members should be considered when overriding GetHashCode and Equals? C#运算符重载:Object.Equals(object o)和Object.GetHashCode() - C# operator overloading: Object.Equals(object o) & Object.GetHashCode() static Object.Equals方法,GetHashCode的默认实现和Dictionary类 - static Object.Equals method, default implementation of GetHashCode and the Dictionary class 如何在 C# “object.equals”中使用“或”(|)运算符 - How do I use “or” (|) operator in C# “object.equals” 所有c#类应该实现Equals和GetHashCode吗? - should all c# classes implement Equals and GetHashCode? Char.Equals vs Object.Equals - ReSharper建议我应该使用Object.Equals。 我是不是该? - Char.Equals vs Object.Equals — ReSharper suggests that I should use Object.Equals. Should I? C# 覆盖 GetHashCode 方法 - C# Overriding the GetHashCode method 带有多个或条件的 C# Object.Equals() - C# Object.Equals() with multiple or conditions
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM