8

2 つの文字列と列挙型で構成されるクラスがあります。このクラスのインスタンスを辞書のキーとして使用しようとしています。残念ながら、私は 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);
    }

誰かが私が間違っているところを指摘できますか? かなり単純なものが欠けていると確信していますが、何がわかりません。

4

1 に答える 1

8

あなたのクラスはオーバーライドする必要がEqualsありますGetHashCode

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に従ってアルゴリズムも改善したことに注意してください:オーバーライドされた 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をオーバーライドする必要がなくなりました:EqualsGetHashCode

var dict = new Dictionary<CoinDetails, string>(new CoinComparer());
dict.Add(new CoinDetails("1POUND", "1997"), "");
dict.Add(new CoinDetails("1POUND", "1997"), ""); // FAIL!!!!
于 2014-03-04T15:00:57.413 に答える