編集: System.HashCode
リリースされました。ハッシュコードを作成する推奨される方法は次のとおりです。
public override int GetHashCode()
{
return HashCode.Combine(fieldA, fieldB, fieldC);
}
System.HashCode.Combine()
各フィールドを内部的に呼び出し.GetHashCode()
、正しいことを自動的に行います。
非常に多くのフィールド (8 つ以上) の場合、インスタンスを作成してからメソッドHashCode
を使用できます。.Add()
public override int GetHashCode()
{
HashCode hash = new HashCode();
hash.Add(fieldA);
hash.Add(fieldB);
hash.Add(fieldC);
hash.Add(fieldD);
hash.Add(fieldE);
hash.Add(fieldF);
hash.Add(fieldG);
hash.Add(fieldH);
hash.Add(fieldI);
return hash.ToHashCode();
}
Visual Studio 2019 には、生成するクイック アクション ヘルパーが追加されEquals()
ましGetHashCode()
た。宣言内のクラス名を右クリックし、[クイック アクションとリファクタリング] > [Equals と GetHashCode を生成] をクリックします。等価に使用するメンバーを選択し、「Implement IEquatable」も選択して、[OK] をクリックします。
最後にもう 1 つ: オブジェクトの構造ハッシュ コードを取得する必要がある場合、たとえば、参照ではなく内容(別名構造) に基づいて変化する配列のハッシュ コードを含めたい場合は、キャストする必要があります。次のように、フィールドを手動で取得し、そのハッシュ コードを手動で取得します。IStructuralEquatable
public override int GetHashCode()
{
return HashCode.Combine(
fieldA,
((IStructuralEquatable)stringArrayFieldB).GetHashCode(EqualityComparer<string>.Default));
}
これは、IStructuralEquatable
ほとんどの場合、インターフェイスが明示的に実装されているためです。そのため、デフォルトメソッドの代わりに へのキャストIStructuralEquatable
を呼び出す必要があります。IStructuralEquatable.GetHashCode()
object.GetHashCode()
最後に、現在の実装で.GetHashCode
は、 のint
は単に整数値そのものであるためHashCode.Combine()
、フィールド自体の代わりに にハッシュコード値を渡しても、結果に違いはありません。
古い答え:
完全を期すために、.NET タプル リファレンス ソースの 52 行目にあるハッシュ アルゴリズムを次に示します。興味深いことに、このハッシュ アルゴリズムは からコピーされたものSystem.Web.Util.HashCodeCombiner
です。
コードは次のとおりです。
public override int GetHashCode() {
// hashing method taken from .NET Tuple reference
// expand this out to however many items you need to hash
return CombineHashCodes(this.item1.GetHashCode(), this.item2.GetHashCode(), this.item3.GetHashCode());
}
internal static int CombineHashCodes(int h1, int h2) {
// this is where the magic happens
return (((h1 << 5) + h1) ^ h2);
}
internal static int CombineHashCodes(int h1, int h2, int h3) {
return CombineHashCodes(CombineHashCodes(h1, h2), h3);
}
internal static int CombineHashCodes(int h1, int h2, int h3, int h4) {
return CombineHashCodes(CombineHashCodes(h1, h2), CombineHashCodes(h3, h4));
}
internal static int CombineHashCodes(int h1, int h2, int h3, int h4, int h5) {
return CombineHashCodes(CombineHashCodes(h1, h2, h3, h4), h5);
}
internal static int CombineHashCodes(int h1, int h2, int h3, int h4, int h5, int h6) {
return CombineHashCodes(CombineHashCodes(h1, h2, h3, h4), CombineHashCodes(h5, h6));
}
internal static int CombineHashCodes(int h1, int h2, int h3, int h4, int h5, int h6, int h7) {
return CombineHashCodes(CombineHashCodes(h1, h2, h3, h4), CombineHashCodes(h5, h6, h7));
}
internal static int CombineHashCodes(int h1, int h2, int h3, int h4, int h5, int h6, int h7, int h8) {
return CombineHashCodes(CombineHashCodes(h1, h2, h3, h4), CombineHashCodes(h5, h6, h7, h8));
}
もちろん、実際の Tuple GetHashCode()
(実際には) には、保持しているアイテムの数に基づいて、これらのどれを呼び出すかを決定するInt32 IStructuralEquatable.GetHashCode(IEqualityComparer comparer)
大きなブロックがあります。独自のコードでは、おそらくそれを必要としません。switch