0

私はこれに似たクラスを持っています:

public class Int16_2D
{
    public Int16 a, b;

    public override bool Equals(Object other)
    {
        return other is Int16_2D &&
        a == ((Int16_2D)other).a &&
        b == ((Int16_2D)other).b;
    }
}

これはで動作しHashSet<Int16_2D>ます。ただし、Dictionary<Int16_2D, myType>では、.ContainsKeyすべきでないときにfalseを返します。の実装に何かが欠けてい==ますか?

4

4 に答える 4

3

GetHashCode()クラスがハッシュテーブルまたはディクショナリで機能するには、 !を実装する必要があります。なぜHashSetで機能するのかわかりません。運が良かったと思います。

EqualsまたはGetHashCode()の計算に可変フィールドを使用するのは危険であることに注意してください。なんで?このことを考慮:

var x = new Int16_2D { a = 1, b = 2 };
var set = new HashSet<Int16_2D> { x };

var y = new Int16_2D { a = 1, b = 2 };
Console.WriteLine(set.Contains(y));   // True

x.a = 3;
Console.WriteLine(set.Contains(y));   // False
Console.WriteLine(set.Contains(x));   // Also false!

つまり、設定x.a = 3;すると、xのハッシュコードが変更されます。ただし、ハッシュテーブル内のxの位置は古いハッシュコードに基づいているため、xは基本的に失われます。http://ideone.com/QQw08でこれを実際に見てください

また、svickが指摘しているように、実装は実装Equalsしません==。を実装しない場合====演算子は参照比較を提供するため、次のようになります。

var x = new Int16_2d { a = 1, b = 2 };
var y = new Int16_2d { a = 1, b = 2 };
Console.WriteLine(x.Equals(y));             //True
Console.WriteLine(x == y);                  //False

結論として、これを不変のタイプにする方がよいでしょう。たった4バイトの長さなので、おそらく不変の構造体にします。

于 2012-04-14T16:33:00.613 に答える
2

をオーバーライドする必要がありますGetHashCode()。それが機能するという事実HashSet<T>は、おそらく幸運な偶然です。

どちらのコレクションも、から取得したハッシュコードを使用してGetHashCode、オブジェクトを配置するバケット(つまり、オブジェクトのリスト)を検索します。次に、そのバケットを検索してオブジェクトを見つけ、を使用Equalsして同等性を確保します。これは、DictionaryとHashSetの優れた高速ルックアッププロパティを提供するものです。ただし、これはGetHashCode、typesEqualsメソッドに対応するようにオーバーライドされていない場合、コレクションの1つでそのようなオブジェクトを見つけることができないことも意味します。

ほとんどの場合、との両方GetHashCodeを実装するEqualsか、どちらも実装しないでください。

于 2012-04-14T16:32:02.900 に答える
0

GetHashCode辞書を機能させるには、同様にオーバーライドする必要があります。

于 2012-04-14T16:31:56.343 に答える
0

GetHashCode()同様にオーバーライドする必要があります-これはオーバーライドと密接に関連していますEquals。ディクショナリはGetHashCode()、値がどのビンに分類されるかを決定するために使用します。そのビンで適切なアイテムが見つかった場合にのみ、アイテムの実際の同等性をチェックします。

于 2012-04-14T16:32:06.837 に答える