20

この記事で、Jon Skeet は、通常はこの種のアルゴリズムを使用してGetHashCode()をオーバーライドすると述べました。

public override int GetHashCode()
{
  unchecked // Overflow is fine, just wrap
  {
    int hash = 17;
    // Suitable nullity checks etc, of course :)
    hash = hash * 23 + Id.GetHashCode();
    return hash;
  }
}

今、私はこれを使用してみましたが、Resharper はメソッドGetHashCode()が読み取り専用フィールドのみを使用してハッシュする必要があることを教えてくれます (ただし、正常にコンパイルされます)。現在、自分のフィールドを読み取り専用にすることは本当にできないので、どのような良い習慣がありますか?

このメソッドを Resharper で生成してみました。結果は次のとおりです。

public override int GetHashCode()
{
  return base.GetHashCode();
}

正直なところ、これはあまり貢献していません...

4

3 に答える 3

18

すべてのフィールドが変更可能で、GetHashCodeメソッドを実装する必要がある場合、これが必要な実装であると思います。

public override int GetHashCode() 
{ 
    return 1; 
} 

はい、これは非効率的ですが、少なくとも正しいです。

問題は、GetHashCode各アイテムをバケットに配置するために Dictionary および HashSet コレクションによって使用されていることです。いくつかの変更可能なフィールドに基づいてハッシュコードが計算され、オブジェクトが HashSet または Dictionary に配置された後にフィールドが実際に変更された場合、そのオブジェクトは HashSet または Dictionary から見つけることができなくなります。

すべてのオブジェクトが同じ HashCode 1 を返すということは、基本的に、すべてのオブジェクトが HashSet または Dictionary の同じバケットに入れられることを意味することに注意してください。したがって、HashSet または Dictionary には常に 1 つのバケットしかありません。オブジェクトを検索しようとすると、唯一のバケット内の各オブジェクトに対して同等性チェックが行われます。これは、リンクされたリストで検索を行うようなものです。

オブジェクトが HashCode または Dictionary コレクションに追加された後にフィールドが決して変更されないことを確認できれば、変更可能なフィールドに基づいてハッシュコードを実装しても問題ないと主張する人がいるかもしれません。私の個人的な見解では、これはエラーが発生しやすいということです。2 年後にあなたのコードを引き継ぐ誰かが、これに気づかず、誤ってコードを壊してしまう可能性があります。

于 2012-07-14T06:18:31.897 に答える
5

GetHashCode は Equals メソッドと連携する必要があることに注意してください。また、参照の等価性を使用できる場合 (クラスの 2 つの異なるインスタンスが等しくない場合) は、Object から継承された Equals と GetHashCode を安全に使用できます。return 1これは、単純に GetHashCode を使用するよりもはるかにうまく機能します。

于 2012-07-14T15:39:22.897 に答える