2015-09-27 4 views
5

匿名クラスの実装をGetHashCode()にすると、Roslynはプロパティ名に基づいて初期ハッシュ値を計算します。匿名クラスに対して生成されたGetHashCode()実装の初期ハッシュ値がプロパティ名に依存するのはなぜですか?

public override in GetHashCode() 
{ 
    int hash = 339055328; 
    hash = hash * -1521134295 + EqualityComparer<int>.Default.GetHashCode(Int); 
    hash = hash * -1521134295 + EqualityComparer<string>.Default.GetHashCode(Text); 
    return hash; 
} 

しかし、我々は、プロパティ名、初期値の変更変更した場合::

var x = new { Int2 = 42, Text2 = "42" }; 

public override in GetHashCode() 
{ 
    int hash = 605502342; 
    hash = hash * -1521134295 + EqualityComparer<int>.Default.GetHashCode(Int2); 
    hash = hash * -1521134295 + EqualityComparer<string>.Default.GetHashCode(Text2); 
    return hash; 
} 

例えば、

var x = new { Int = 42, Text = "42" }; 

のために生成されたクラスは、次のGetHashCode()の方法を持っているとしていますこの行動の背後にある理由は何ですか?大きな[素数]の番号を選んでそれをすべての匿名クラスに使用するだけで問題はありますか?

+0

異なるタイプのオブジェクトが「より」異なるように異なる定数を使用すると、私にとってはもっと役に立つようです。 – usr

答えて

6

大きな[プライム]番号を選んでそれをすべての匿名クラスに使用するだけで問題はありますか?

これを行うことには何も問題はありませんが、効率の低い値を生成する傾向があります。

GetHashCode実装の目標は、等しくない値に対して異なる結果を返すことです。これにより、値がハッシュベースのコレクション(Dictionary<TKey, TValue>など)で使用されるときの衝突の可能性が減少します。

匿名の値が異なるタイプを表す場合、匿名の値は他の匿名の値と等しくなることはありません。匿名の値のタイプは、プロパティの形状によって定義されるプロパティのプロパティ

  • タイプの任意に異なる特性の
  • カウント
  • つの匿名の値

    • 名前これらの特性は異なるタイプを表し、したがって等しい値になることはありません。

      コンパイラがGetHashCodeの実装を生成するのは理にかなっており、異なるタイプの異なる値を返す傾向があります。このため、最初のハッシュを計算するときには、the compilerにプロパティ名が含まれています。

    +0

    私は参照してください。何らかの理由で 'HashSet 'に異なる型のインスタンスを置くと、一定の初期値を持つハッシュコードがあなたの顔に爆発する可能性があります。 – HellBrick

    +0

    しかし、異なる型のオブジェクトを区別するハッシュが一般的には良い考えですが、なぜ匿名クラスはデフォルトで完了するのか?私はBCLで​​これの一例をまだ見つけていません。たとえば、Int64、TimeSpan、DateTimeは基本的に実装を共有し、 '0L.GetHashCode()' == 'TimeSpan.Zero.GetHashCode()' == 'default(DateTime).GetHashCode()'を共有します。 – HellBrick

    +0

    @HellBrick差異化は、値が同じハッシュ構造に挿入される可能性が高い場合にのみ興味深いです。実際には、異なるタイプの匿名の値がこれを行うのは珍しいことではありません。しかし、ハッシュ構造には、DateTimeとTimeSpanの両方の値がキーとして設定されることはほとんどありません。 – JaredPar

    4

    Roslynチームの誰かがステップアップしない限り、私たちは推測することしかできません。私は同じ方法でそれをやっただろう。匿名型ごとに異なるシードを使用することは、ハッシュコードでよりランダム性を持たせるのに便利です。たとえば、new { a = 1 }.GetHashCode() != new { b = 1 }.GetHashCode()が真となります。

    また、ハッシュコード計算が崩壊する原因となる不良シードがあるかどうかも疑問です。私はそうは思わない。 0の種子でも動作します。

    RoslynソースコードはAnonymousTypeGetHashCodeMethodSymbolにあります。初期ハッシュコード値は、匿名型の名前のハッシュに基づいています。

    関連する問題