2014-03-04 24 views
4

我有一個由兩個字符串和一個枚舉組成的類。我試圖將這個類的實例用作字典中的鍵。不幸的是,我似乎沒有正確實施IEquatable。以下是我如何做到這一點:IEquatable的類實現用作字典中的鍵

public enum CoinSide 
{ 
    Heads, 
    Tails 
} 

public class CoinDetails : IComparable, IEquatable<CoinDetails> 
{ 
    private string denomination; 
    private string design; 
    private CoinSide side; 

//... 

    public int GetHashCode(CoinDetails obj) 
    { 
     return string.Concat(obj.Denomination, obj.Design, obj.Side.ToString()).GetHashCode(); 
    } 

    public bool Equals(CoinDetails other) 
    { 
     return (this.Denomination == other.Denomination && this.Design == other.Design && this.Side == other.Side); 
    } 
} 

但是,我仍然無法在我的字典中查找項目。此外,以下測試失敗:

[TestMethod] 
    public void CoinDetailsHashCode() 
    { 
     CoinDetails a = new CoinDetails("1POUND", "1997", CoinSide.Heads); 
     CoinDetails b = new CoinDetails("1POUND", "1997", CoinSide.Heads); 
     Assert.AreEqual(a.GetHashCode(), b.GetHashCode()); 
    } 

    [TestMethod] 
    public void CoinDetailsCompareForEquality() 
    { 
     CoinDetails a = new CoinDetails("1POUND", "1997", CoinSide.Heads); 
     CoinDetails b = new CoinDetails("1POUND", "1997", CoinSide.Heads); 
     Assert.AreEqual<CoinDetails>(a, b); 
    } 

有人能夠指出我要去哪裏錯了嗎?我確信我錯過了一些相當簡單的事情,但我不確定是什麼。

+0

您還沒有覆蓋'布爾等於(對象)'這大概就是爲什麼測試失敗。儘管如此,我希望字典可以。如果您可以顯示一個簡短但完整的程序來演示問題,那將會有所幫助。 –

回答

5

你班有EqualsGetHashCode覆蓋:

public class CoinDetails 
{ 
    private string Denomination; 
    private string Design; 
    private CoinSide Side; 

    public override bool Equals(object obj) 
    { 
     CoinDetails c2 = obj as CoinDetails; 
     if (c2 == null) 
      return false; 
     return Denomination == c2.Denomination && Design == c2.Design; 
    } 

    public override int GetHashCode() 
    { 
     unchecked 
     { 
      int hash = 17; 
      hash = hash * 23 + (Denomination ?? "").GetHashCode(); 
      hash = hash * 23 + (Design ?? "").GetHashCode(); 
      return hash; 
     } 
    } 
} 

請注意,我也提高了你的GetHashCode算法根據:What is the best algorithm for an overridden System.Object.GetHashCode?

您還可以通過自定義IEqualityComparer<CoinDetail>到字典:

public class CoinComparer : IEqualityComparer<CoinDetails> 
{ 
    public bool Equals(CoinDetails x, CoinDetails y) 
    { 
     if (x == null || y == null) return false; 
     if(object.ReferenceEquals(x, y)) return true; 
     return x.Denomination == y.Denomination && x.Design == y.Design; 
    } 

    public int GetHashCode(CoinDetails obj) 
    { 
     unchecked 
     { 
      int hash = 17; 
      hash = hash * 23 + (obj.Denomination ?? "").GetHashCode(); 
      hash = hash * 23 + (obj.Design ?? "").GetHashCode(); 
      return hash; 
     } 
    }      
} 

現在這個工作,並不需要CoinDetails覆蓋Equals + GetHashCode

var dict = new Dictionary<CoinDetails, string>(new CoinComparer()); 
dict.Add(new CoinDetails("1POUND", "1997"), ""); 
dict.Add(new CoinDetails("1POUND", "1997"), ""); // FAIL!!!! 
+0

我刪除了IEquatable引用,並將方法更改爲覆蓋,這使程序可以正常運行。我現在正在閱讀「最佳哈希碼」文章,並可能會相應地做出更改。非常感謝你! – user2823789

+0

@ user2823789:請注意,我還編輯了我的答案,以提供另一種不需要修改類本身的方法。 –

+0

是的,我注意到了。不過,我認爲我會堅持壓倒他們。另外,有趣的是,23是顯然對於在改進的哈希碼算法的質數中的一個不好的選擇,因爲: 「23沒有很好的選擇,因爲(如.NET 3.5 SP1的)字典假定良好分佈模某些質數。 23是其中之一,所以如果你有一個容量爲23的字典,那麼只有對GetHashCode的最後一個貢獻會影響複合散列碼,所以我寧願用29代替23。 儘管如此,你一直非常有幫助,所以謝謝。 – user2823789