2012-09-26 30 views
0

我讀到this question here,這導致我this article here我可以實現一個基本的GetHashCode(),它可以用於我的抽象基類的所有擴展?

我有一個抽象的基類,允許我限制方法只接受我的類擴展我的抽象基類(基本多態性)。我的問題是:我可以在抽象基類中實現GetHashCode()以爲任何具體實現提供合適的重寫嗎? (即以避免在每個具體類中重寫GetHashCode()。)

我想象在我的抽象基類,像這樣的方法:

public abstract class FooBase 
{ 
    private static readonly int prime_seed = 13; 
    private static readonly int prime_factor = 7; 

    public override int GetHashCode() 
    { 
     // Seed using the hashcode for this concrete class' Type so 
     // two classes with the same properties return different hashes. 
     int hash = prime_seed * this.GetType().GetHashCode(); 
     // Get this concrete class' public properties. 
     var props = this.GetType().GetProperties(BindingFlags.Public); 
     foreach (var prop in props) 
     { 
      // Factor in each of this concrete class' public properties' hashcodes. 
      hash = (hash * prime_factor) + prop.GetHashCode(); 
     } 
     return hash; 
    } 
} 

這似乎在一些基本的平等單元測試,但我的工作覺得我忽略了一些東西。我仍然需要在每個具體類中提供一個覆蓋,以避免編譯器警告不要覆蓋GetHashCode(),但至少這樣我不必爲每個實現手動編寫實現。

+0

好像它會很慢涉及反射散列 –

+0

接下來,我去了並做了一些關於GetHashCode()和Equals()及其相互關係的實現和使用的更多閱讀。在獲得更好的理解之後,我放棄了上面正在處理的基礎GetHashCode()。排隊其中一箇舊的NBC PSA:更多你知道...... – JMD

+0

重寫'structs'中的'GetHashCode()'總是好的原因之一就是避免使用與此相同的一般思想的默認值。它大部分時間都在使用,但是它比大多數簡單的'GetHashCode()'重寫要慢很多,你可以在一分鐘之內編寫代碼。 –

回答

2

這是否有更好的表現比:

public override int GetHashCode() 
{ 
    return 1; 
} 

一鍵散列函數是它必須快速地計算。通過反思,你可能會失去從散列獲得的所有好處。

這將是值得的基準。

此外,當Equals返回true時,哈希碼必須相等,所以所有子類在其Equals方法中只使用公共屬性嗎?如果不是,你可能會考慮循環所有的屬性,而不僅僅是公共的。

編輯以添加: 另外,考慮在屬性循環周圍添加unchecked以防止發生異常,如果散列值大於Int.MaxValue。

+0

+1尤其是「哈希碼匹配等於」的評論。請注意,由於反射不會使GetHashCode變慢,因爲如果不對對象進行任何更改,結果可以被緩存。問題在於確保對象在調用之間不會發生變化。 –

+0

感謝對性能的懲罰和關於'unchecked'的說明。在我的情況下,我不會處理足夠的對象(可能是幾千個實例),以使性能受到明顯影響。不過,我要回去重新考慮我前進的方向。 – JMD

0

使用反射比較慢,但在某些情況下它是可以接受的。當類的實例是散列表或字典中的鍵時,將使用GetHashCode函數。在大多數情況下,你知道什麼時候需要它。有一些工具,如Resharperexample)可以爲您生成GetHashCode和Equals函數,而不是手動編寫它們。

+0

「在大多數情況下,你知道什麼時候需要它。」哈!我也這麼想!現在我發現,當我使用DevExpress XtraGrid(一個類似網格的控件)並將其綁定到我的對象的List <>時,DevExpress內部有時會使用我的對象作爲鍵創建一個Hashtable。然後它崩潰。呸! – RenniePet

1

您錯過了一條基本規則 - GetHashCode()結果在整個生命週期中必須保持不變。在你的GetHashCode實現中,它不被保證(因爲你正在迭代的屬性可以是可變的)。

+2

-1 - 這是不正確的。如果您查看http://msdn.microsoft.com/en-us/library/system.object.gethashcode。aspx它明確地說「只要*有*沒有修改對象狀態,就必須始終返回相同的哈希碼」 –

+1

Eric Lippert寫道:「規則:GetHashCode返回的整數不能在對象包含在數據中時更改結構依賴於哈希碼保持穩定「。他還寫道,指導方針是結果永遠不會改變。對於他的完整解釋,請閱讀原文:http://blogs.msdn.com/b/ericlippert/archive/2011/02/28/guidelines-and-rules-for-gethashcode.aspx –

+0

這是不可能的如果哈希是從對象的狀態派生的,則GetHashCode()的結果在對象的整個生命週期內保持不變。該規則會使每個使用對象狀態生成散列碼的示例失效。按照規則,從構建開始的那一刻起,您將不允許更改派生哈希碼的任何值。 – JMD

相關問題