1. ホーム
  2. c#

[解決済み] EqualsメソッドがオーバーライドされたときにGetHashCodeをオーバーライドすることが重要な理由は何ですか?

2022-03-14 05:47:41

質問

次のようなクラスがあるとします。

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();
    }
}

をオーバーライドしました。 Equals メソッドは Foo の行を表します。 Foo のテーブルを作成します。 をオーバーライドするには、どちらの方法が望ましいですか? GetHashCode ?

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

解決方法は?

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

は、その GetHashCode() メソッドに反映させる必要があります。 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 .


これを間違えるとどうなるかのデモは こちら .