Equals メソッドをオーバーライドするときに GetHashCode をオーバーライドすることが重要なのはなぜですか? 質問する

Equals メソッドをオーバーライドするときに GetHashCode をオーバーライドすることが重要なのはなぜですか? 質問する

次のクラスを想定する

public class Foo
{
    public int FooId { get; set; }
    public string FooName { get; set; }

    public override bool Equals(object obj)
    {
        Foo fooItem = obj as Foo;

        if (fooItem == null) 
        {
           return false;
        }

        return fooItem.FooId == this.FooId;
    }

    public override int GetHashCode()
    {
        // Which is preferred?

        return base.GetHashCode();

        //return this.FooId.GetHashCode();
    }
}

は s テーブルの行を表すEqualsため、 メソッドをオーバーライドしました。 をオーバーライドするための推奨される方法はどれですか?FooFooGetHashCode

オーバーライドすることがなぜ重要なのでしょうかGetHashCode?

ベストアンサー1

はい、アイテムが辞書のキーや などとして使用されるかどうかは重要ですHashSet<T>。これは、(カスタム がない場合にIEqualityComparer<T>)アイテムをバケットにグループ化するために使用されるためです。2 つのアイテムのハッシュ コードが一致しない場合は、それらが等しいと見なされることはありません(等しい決して呼び出されることはありません。

ハッシュコードを取得する()メソッドはEqualsロジックを反映する必要があります。ルールは次のとおりです。

  • 2つのものが等しい場合(Equals(...) == true)、それらは同じ値を返す必要がありますGetHashCode()
  • GetHashCode()が等しい場合、それらが同じである必要はありません。これは衝突であり、Equals実際に等しいかどうかを確認するために呼び出されます。

この場合、「return FooId;」が適切なGetHashCode()実装のようです。複数のプロパティをテストする場合は、対角衝突を減らすために、以下のようなコードを使用してそれらを結合するのが一般的です(つまり、 が とはnew Foo(3,5)異なるハッシュコードを持つようにしますnew Foo(5,3))。

最新のフレームワークでは、HashCode型には複数の値からハッシュコードを作成するのに役立つメソッドがありますが、古いフレームワークでは、次のようなメソッドがないため、次のようになります。

unchecked // only needed if you're compiling with arithmetic checks enabled
{ // (the default compiler behaviour is *disabled*, so most folks won't need this)
    int hash = 13;
    hash = (hash * 7) + field1.GetHashCode();
    hash = (hash * 7) + field2.GetHashCode();
    ...
    return hash;
}

ああ、便宜上、 および をオーバーライドするときに および 演算子を提供することも検討==!=くださいEqualsGetHashCode


これを間違えると何が起こるかのデモンストレーションはここ

おすすめ記事