2011-09-05 71 views
10

嗨,我有一個具有6個字符串屬性的類。一個獨特的對象對於這些字段中的至少一個將具有不同的值C#.NET GetHashCode函數問題

要實現IEqualityComparer的GetHashCode函數,我將連接所有6個屬性並在結果字符串上調用GetHashCode。

我有以下疑點:

  1. 是否需要調用GetHashCode的一個獨特的價值?
  2. 對六個屬性的連接操作是否會使比較變慢?
  3. 我應該使用其他方法嗎?
+0

是你計劃比較你的對象在某個地方,比如在一個數組中排序它們?這將改變是否你需要實現GetHashCode – mydogisbox

+0

嗨mydogisbox,我用它的List.Contains方法並將比較對象傳遞給它。我已經實現了Equals,並且不知道GetHashcode的正確方法 – ganeshran

回答

3

GetHashCode並不需要返回的「不平等」的對象不等價。它只需要爲相等的對象返回相等的值(它也必須在對象的生命週期內返回相同的值)。

這意味着:

  1. 如果兩個對象比較Equals爲相等,那麼他們必須GetHashCode返回相同的值。
  2. 如果某些字符串6個屬性沒有嚴格只讀的,他們不能把在GetHashCode實現部分。

如果你不能同時滿足這兩點,那麼你應該重新評估你的設計,因爲其他任何事情都會爲漏洞開放。

最後,您可以通過在6個字符串的每一個上調用GetHashCode,然後使用一些按位操作將所有6個結果集成一個值,使得GetHashCode速度更快。

+0

嗨喬恩,我的任何屬性都是隻讀的。但是,它們都有私人設置器,所以只能從構造器中進行修改。這會影響他們在GetHashCode中的使用嗎? – ganeshran

+0

@ ganeshran:那麼它們在對象的整個生命週期內是有效的只讀(即,如果你願意,它們可以用'readonly'後臺字段來實現),這就足夠了。你會沒事的。 – Jon

+0

@Jon讀取你的GetHashCode()實現的條件,我發現它是一個需求衝突的問題。事實上,你只是部分正確。 GetHashCode()方法的實際要求是: 1.它應該爲相等的對象返回相同的值。 2.對於同一個對象,當它沒有被修改時,它應該返回相同的值。 3. GetHashCode()應該很快。 同意,還有一些其他建議。例如這一個:爲了獲得最佳性能,散列函數應該爲所有輸入生成一個隨機分佈。 –

3

如果您在這些對象上調用Equals(),則GetHashCode()應該爲所有返回true的對象返回相同的哈希碼。這意味着,例如,無論字段值是什麼,您都可以返回零作爲散列碼。但是,如果存儲在哈希表等數據結構中,這會使對象非常低效。

結合弦是一種選擇,但請注意,例如,您可以結合只是stringsfor的哈希碼(同時仍然處於比較平等的所有字符串!)兩種。

您也可以結合六個單獨字符串的哈希值,而不是計算一個散列組合的字符串。看例如 Quick and Simple Hash Code Combinations

我不知道這是否會比連接字符串顯着更快。

+0

謝謝Anders,我僅將它用於Contains方法比較。如果我只爲散列碼組合兩個字符串,如果對象中的兩個值是相同的,那麼這些散列碼是不會相同的?這會混淆比較,還是GetHashCode對比較本身沒有影響,並且只會影響性能 – ganeshran

+1

其他人已經提出這一點,但我想用不同的方式來解決它,因爲它看起來是你的直覺卡住。注意到GetHashCode()返回一個int,它只能取得2^32個不同的值。你的對象由6個任意長度的字符串組成,顯然可以帶有大量的值。通過這個例子,我們可以很容易地看到GetHashCode()不可能是對象的所有可能值的唯一值。它只能滿足這個屬性:「if a.Equals(b)then a.GetHashCode()== b.GetHashCode()」;並注意到「如果」不能雙向進行。 –

+1

GetHashCode()的實際考慮因素是「好」和「快」。爲了使它「快」,我會盡量避免所有的內存分配和字符串複製;使它「好」是一個細微差別的主題,但在實踐中,像@Jon所建議的那樣,將子對象的GetHashCode()值混合在一起就足夠了。我將發佈ReSharper的建議作爲「答案」,以便我可以獲取代碼格式。 –

4

如果字符串字段AF命名,並已知不爲空,這是ReSharper的建議,爲您的GetHashCode()

public override int GetHashCode() { 
    unchecked { 
    int result=a.GetHashCode(); 
    result=(result*397)^b.GetHashCode(); 
    result=(result*397)^c.GetHashCode(); 
    result=(result*397)^d.GetHashCode(); 
    result=(result*397)^e.GetHashCode(); 
    result=(result*397)^f.GetHashCode(); 
    return result; 
    } 
} 
+0

謝謝,我將使用此代碼。 – ganeshran

+0

在這裏看到我的答案:http://stackoverflow.com/a/34006336/1911540 –