次のクラスを想定する
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
ため、 メソッドをオーバーライドしました。 をオーバーライドするための推奨される方法はどれですか?Foo
Foo
GetHashCode
オーバーライドすることがなぜ重要なのでしょうか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;
}
ああ、便宜上、 および をオーバーライドするときに および 演算子を提供することも検討し==
て!=
ください。Equals
GetHashCode
これを間違えると何が起こるかのデモンストレーションはここ。