28

次のオブジェクトについて考えてみます。

class Route
{
   public int Origin { get; set; }
   public int Destination { get; set; }
}

ルートは等式演算子を実装します。

class Routing
{
   public List<Route> Paths { get; set; }
}

以下のコードを使用してRoutingオブジェクトのGetHashCodeメソッドを実装しましたが、機能しているようですが、それが正しい方法かどうか疑問に思います。私は平等チェックに頼っていますが、よくわからないので皆さんに聞いてみようと思いました。ハッシュコードを合計するだけですか、それとも目的の効果を保証するためにさらに魔法をかける必要がありますか?

public override int GetHashCode() =>
{
    return (Paths != null 
                ? (Paths.Select(p => p.GetHashCode())
                        .Sum()) 
                : 0);
}

ここでいくつかのGetHashCode()質問と、このトピックに関するMSDNとEric Lippertの記事を確認しましたが、探しているものが見つかりませんでした。

4

4 に答える 4

18

あなたの解決策は大丈夫だと思います。(ずっと後のコメント:LINQのSumメソッドはcheckedコンテキストで動作するので、非常に簡単に取得できますOverflowException。つまり、結局のところ、それほど細かくはありません。)しかし、XOR(キャリーなしの加算)を実行するのがより一般的です。だからそれは次のようなものかもしれません

public override int GetHashCode()
{
  int hc = 0;
  if (Paths != null)
    foreach (var p in Paths)
      hc ^= p.GetHashCode();
  return hc;
}

補遺(回答が受理された後):

ハッシュテーブルが使用される、、または別の状況でこのタイプを使用する場合、コレクションに追加された後に誰かが変更(変更)すると、インスタンスが失われるRoutingことに注意してください。Dictionary<Routing, Whatever>HashSet<Routing>Routing

それが絶対に起こらないと確信している場合は、上記の私のコードを使用してください。Dictionary<,>参照されているものをだれも変更しないようにすれば、以下同様に機能しますRouting

別の選択肢はただ書くことです

public override int GetHashCode()
{
  return 0;
}

ハッシュコードが使用されることはないと思われる場合。すべてのインスタンスがハッシュコードを返す場合0、ハッシュテーブルのパフォーマンスは非常に悪くなりますが、オブジェクトが失われることはありません。3番目のオプションは、をスローすることNotSupportedExceptionです。

于 2012-05-12T21:24:17.913 に答える
10

Jeppe Stig Nielsenの回答のコードは機能しますが、ハッシュコード値の繰り返しにつながる可能性があります。0〜100の範囲のintのリストをハッシュしているとすると、ハッシュコードは0〜255の範囲であることが保証されます。これにより、辞書で使用すると多くの衝突が発生します。改善されたバージョンは次のとおりです。

public override int GetHashCode()
{
  int hc = 0;
  if (Paths != null)
    foreach (var p in Paths) {
        hc ^= p.GetHashCode();
        hc = (hc << 7) | (hc >> (32 - 7)); //rotale hc to the left to swipe over all bits
    }
  return hc;
}

このコードは、ハッシュされるアイテムが増えるにつれて、少なくとも時間の経過とともにすべてのビットを含みます。

于 2012-05-12T21:30:04.123 に答える
6

ガイドラインとして、オブジェクトのハッシュは、オブジェクトの存続期間全体にわたって同じである必要があります。関数はそのままにして、GetHashCode上書きしません。ハッシュコードは、オブジェクトをハッシュテーブルに配置する場合にのみ使用されます。

.NETのハッシュコードに関するEricLippertのすばらしい記事:GetHashCodeのガイドラインとルールを読む必要があります。

その記事からの引用:

ガイドライン:GetHashCodeによって返される整数は決して変更されるべきではありません

規則:GetHashCodeによって返される整数は、オブジェクトが安定したままのハッシュコードに依存するデータ構造に含まれている間は決して変更してはなりません。

オブジェクトがハッシュテーブルにあるときにオブジェクトのハッシュコードが変化する可能性がある場合は、Containsメソッドが機能しなくなることは明らかです。オブジェクトをバケット#5に入れて変異させ、変異したオブジェクトが含まれているかどうかをセットに尋ねると、バケット#74を調べても、オブジェクトは見つかりません。

実装したGetHashCode関数は、オブジェクトの存続期間にわたって同じハッシュコードを返しません。この関数を使用する場合、これらのオブジェクトをハッシュテーブルに追加すると、問題が発生しますContainsメソッドは機能しません

于 2012-05-12T21:25:44.137 に答える
0

私はそれが正しい方法だとは思いませんhashcode。指定されたオブジェクトに対して一意である必要がある最終的なものを決定する原因になります。あなたの場合、あなたはを行います。これは、コレクション内の異なるハッシュコードで同じSum()結果を生成する可能性があります(最後にハッシュコードは単なる整数です)。

コレクションの内容に基づいて同等性を判断する場合は、この時点で、2つのオブジェクト間のこれらの選択を比較してください。ちなみに、これは時間のかかる操作かもしれません。

于 2012-05-12T21:22:03.197 に答える