3

このテストは失敗しています:

var hashCode = new 
{
    CustomerId = 3354,
    ServiceId = 3,
    CmsThematicId = (int?)605,
    StartDate = (DateTime?)new DateTime(2013, 1, 5),
    EndDate = (DateTime?)new DateTime(2013, 1, 6)
}.GetHashCode();
var hashCode2 = new
{
    CustomerId = 1210,
    ServiceId = 3,
    CmsThematicId = (int?)591,
    StartDate = (DateTime?)new DateTime(2013, 3, 31),
    EndDate = (DateTime?)new DateTime(2013, 4, 1)
}.GetHashCode();
Assert.AreNotEqual(hashCode, hashCode2);

なぜか教えてくれますか ?

4

4 に答える 4

3

この偶然を見つけたのはちょっとすごいです。

匿名クラスには、GetHashCode()すべてのプロパティのハッシュ コードを組み合わせてハッシュ コードを生成する generated メソッドがあります。

計算は基本的に次のとおりです。

  public override int GetHashCode()
  {
    return        -1521134295 * 
                ( -1521134295 * 
                ( -1521134295 * 
                ( -1521134295 * 
                ( -1521134295 * 
                   1170354300 + 
                  CustomerId.GetHashCode()) +
                  ServiceId.GetHashCode()) + 
                  CmsThematicId.GetHashCode()) + 
                  StartDate.GetHashCode()) + 
                  EndDate.GetHashCode();
  }

いずれかのフィールドの値を変更すると、ハッシュ コードが変更されます。同じハッシュ コードを取得する 2 つの異なる値のセットを見つけたという事実は、偶然の一致です。

ハッシュ コードは必ずしも一意ではないことに注意してください。ハッシュ コードよりも多くのオブジェクトが存在する可能性があるため、ハッシュ コードが常に一意であるとは言えません (ただし、それは多くのオブジェクトです)。適切なハッシュ コードは、値のランダムな分布を提供します。

注: 上記は .NET 4 のものです。異なるバージョンの .NET は異なる場合があり、Mono も異なります。

実際に 2 つのオブジェクトの等価性を比較したい場合は、 を使用します.Equals()。匿名オブジェクトの場合、各フィールドを比較します。さらに良いオプションは、各フィールドを比較し、どのフィールドが異なるかを報告する NUnit 制約を使用することです。ここに制約を投稿しました:

https://stackoverflow.com/a/2046566/118703

于 2013-01-29T14:31:58.337 に答える
1

かなり大量のデータを処理しているときにこれに遭遇しましたか?

ハッシュコードの素晴らしい世界へようこそ。ハッシュ コードは「一意の識別子」ではありません。それはできません。その匿名型の可能な異なるインスタンスの数は本質的に無限にありますが、可能なハッシュ コードは 2^32 のみです。したがって、これらのオブジェクトを十分に作成すると、いくつかの重複が表示されることが保証されます。実際、これらのオブジェクトをランダムに 70,000 個生成した場合、そのうちの 2 つが同じハッシュ コードを持つ確率は 50% を超えます。

詳細については、誕生日、乱数、ハッシュ コード、およびリンクされたウィキペディアの記事を参照してください。

重複が見られなかった人と見られた人がいる理由については、異なるバージョンの .NET でプログラムを実行した可能性があります。ハッシュ コードを生成するためのアルゴリズムは、バージョンまたはプラットフォーム間で同じままであるとは限りません。

オブジェクトの GetHashCode メソッドは、オブジェクトの Equals メソッドの戻り値を決定するオブジェクトの状態に変更がない限り、一貫して同じハッシュ コードを返す必要があります。これはアプリケーションの現在の実行にのみ当てはまり、アプリケーションが再度実行されると別のハッシュ コードが返される可能性があることに注意してください

于 2013-01-29T14:45:16.230 に答える
1

あなたのテストは無効です。

ハッシュ コードは一意であることが保証されていないため (適切な説明については、他の回答を参照してください)、ハッシュ コードの一意性をテストしないでください。

独自のGetHashCode()メソッドを作成するときは、一意性だけでなく、ランダムな入力が均等に分散されているかどうかをテストすることをお勧めします。十分なランダム入力を使用して、適切なテストを取得するようにしてください。

GetHashCode の MSDN 仕様には、具体的に次のように記載されています。

最高のパフォーマンスを得るには、ハッシュ関数がすべての入力に対してランダムな分布を生成する必要があります。

もちろん、これはすべて相対的なものです。100 個のオブジェクトをディクショナリに入れるために使用されるメソッドは、10,000,000 個のオブジェクトをディクショナリに入れるGetHashCode()場合ほどランダムである必要はありません。GetHashCode()

于 2013-01-29T15:22:22.897 に答える
0

ジムは私に (チャット ルームで) 自分のパラメーターを保存するように提案しました。そのため、パラメーターを表示するときに使用されていないものを選択し、誰かが登録したときに使用済みとしてフラグを立てます。しかし、すべてのパラメーターを生成するのは大きな PITA です。

だから私の解決策は、このようなint64ハッシュコードを構築することです

const long i = -1521134295;    
return -i * (-i * (-i * (-i * -117147284 + customerId.GetHashCode()) + serviceId.GetHashCode()) + cmsThematicId.GetHashCode()) + startDate.GetHashCode();

その値はserviceIdとstartDateに依存していたため、終了日を削除しました。最初にこれをハッシュコードに追加するべきではありませんでした。生成されたクラスの逆コンパイルからコピー/貼り付けしました。300 000 の異なる組み合わせでテストを行った場合、衝突は発生しませんでした。

于 2013-01-31T12:50:26.137 に答える