簡體   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