Object.GetHashCode メソッド
定義
重要
一部の情報は、リリース前に大きく変更される可能性があるプレリリースされた製品に関するものです。 Microsoft は、ここに記載されている情報について、明示または黙示を問わず、一切保証しません。
既定のハッシュ関数として機能します。
public:
virtual int GetHashCode();
public virtual int GetHashCode ();
abstract member GetHashCode : unit -> int
override this.GetHashCode : unit -> int
Public Overridable Function GetHashCode () As Integer
戻り値
現在のオブジェクトのハッシュ コード。
例
型と同じまたは小さい範囲の数値のハッシュ コードを計算する最も簡単な方法の Int32 1 つは、その値を単に返す方法です。 次の例は、 構造体のこのような実装を Number
示しています。
using System;
public struct Number
{
private int n;
public Number(int value)
{
n = value;
}
public int Value
{
get { return n; }
}
public override bool Equals(Object obj)
{
if (obj == null || ! (obj is Number))
return false;
else
return n == ((Number) obj).n;
}
public override int GetHashCode()
{
return n;
}
public override string ToString()
{
return n.ToString();
}
}
public class Example
{
public static void Main()
{
Random rnd = new Random();
for (int ctr = 0; ctr <= 9; ctr++) {
int randomN = rnd.Next(Int32.MinValue, Int32.MaxValue);
Number n = new Number(randomN);
Console.WriteLine("n = {0,12}, hash code = {1,12}", n, n.GetHashCode());
}
}
}
// The example displays output like the following:
// n = -634398368, hash code = -634398368
// n = 2136747730, hash code = 2136747730
// n = -1973417279, hash code = -1973417279
// n = 1101478715, hash code = 1101478715
// n = 2078057429, hash code = 2078057429
// n = -334489950, hash code = -334489950
// n = -68958230, hash code = -68958230
// n = -379951485, hash code = -379951485
// n = -31553685, hash code = -31553685
// n = 2105429592, hash code = 2105429592
open System
[<Struct; CustomEquality; NoComparison>]
type Number(value: int) =
member _.Value = value
override _.Equals(obj) =
match obj with
| :? Number as n ->
n.Value = value
| _ -> false
override _.GetHashCode() =
value
override _.ToString() =
string value
let rnd = Random()
for _ = 0 to 9 do
let randomN = rnd.Next(Int32.MinValue, Int32.MaxValue)
let n = Number randomN
printfn $"n = {n,12}, hash code = {n.GetHashCode(),12}"
// The example displays output like the following:
// n = -634398368, hash code = -634398368
// n = 2136747730, hash code = 2136747730
// n = -1973417279, hash code = -1973417279
// n = 1101478715, hash code = 1101478715
// n = 2078057429, hash code = 2078057429
// n = -334489950, hash code = -334489950
// n = -68958230, hash code = -68958230
// n = -379951485, hash code = -379951485
// n = -31553685, hash code = -31553685
// n = 2105429592, hash code = 2105429592
Public Structure Number
Private n As Integer
Public Sub New(value As Integer)
n = value
End Sub
Public ReadOnly Property Value As Integer
Get
Return n
End Get
End Property
Public Overrides Function Equals(obj As Object) As Boolean
If obj Is Nothing OrElse Not TypeOf obj Is Number Then
Return False
Else
Return n = CType(obj, Number).n
End If
End Function
Public Overrides Function GetHashCode() As Integer
Return n
End Function
Public Overrides Function ToString() As String
Return n.ToString()
End Function
End Structure
Module Example
Public Sub Main()
Dim rnd As New Random()
For ctr As Integer = 0 To 9
Dim randomN As Integer = rnd.Next(Int32.MinValue, Int32.MaxValue)
Dim n As New Number(randomN)
Console.WriteLine("n = {0,12}, hash code = {1,12}", n, n.GetHashCode())
Next
End Sub
End Module
' The example displays output like the following:
' n = -634398368, hash code = -634398368
' n = 2136747730, hash code = 2136747730
' n = -1973417279, hash code = -1973417279
' n = 1101478715, hash code = 1101478715
' n = 2078057429, hash code = 2078057429
' n = -334489950, hash code = -334489950
' n = -68958230, hash code = -68958230
' n = -379951485, hash code = -379951485
' n = -31553685, hash code = -31553685
' n = 2105429592, hash code = 2105429592
多くの場合、型にはハッシュ コードの生成に関与できる複数のデータ フィールドがあります。 ハッシュ コードを生成する方法の 1 つは、次の例に示すように、 操作を XOR (eXclusive OR)
使用してこれらのフィールドを結合することです。
using System;
// A type that represents a 2-D point.
public struct Point
{
private int x;
private int y;
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
public override bool Equals(Object obj)
{
if (! (obj is Point)) return false;
Point p = (Point) obj;
return x == p.x & y == p.y;
}
public override int GetHashCode()
{
return x ^ y;
}
}
public class Example
{
public static void Main()
{
Point pt = new Point(5, 8);
Console.WriteLine(pt.GetHashCode());
pt = new Point(8, 5);
Console.WriteLine(pt.GetHashCode());
}
}
// The example displays the following output:
// 13
// 13
// A type that represents a 2-D point.
[<Struct; CustomEquality; NoComparison>]
type Point(x: int, y: int) =
member _.X = x
member _.Y = y
override _.Equals(obj) =
match obj with
| :? Point as p ->
x = p.X && y = p.Y
| _ ->
false
override _.GetHashCode() =
x ^^^ y
let pt = Point(5, 8)
printfn $"{pt.GetHashCode()}"
let pt2 = Point(8, 5)
printfn $"{pt.GetHashCode()}"
// The example displays the following output:
// 13
// 13
' A type that represents a 2-D point.
Public Structure Point
Private x As Integer
Private y As Integer
Public Sub New(x As Integer, y As Integer)
Me.x = x
Me.y = y
End Sub
Public Overrides Function Equals(obj As Object) As Boolean
If Not TypeOf obj Is Point Then Return False
Dim p As Point = CType(obj, Point)
Return x = p.x And y = p.y
End Function
Public Overrides Function GetHashCode() As Integer
Return x Xor y
End Function
End Structure
Public Module Example
Public Sub Main()
Dim pt As New Point(5, 8)
Console.WriteLine(pt.GetHashCode())
pt = New Point(8, 5)
Console.WriteLine(pt.GetHashCode())
End Sub
End Module
前の例では、(n1, n2) と (n2, n1) に対して同じハッシュ コードが返されるため、望ましいよりも多くの競合が発生する可能性があります。 このような場合のハッシュ コードが同一でないように、多くのソリューションを使用できます。 1 つは、各フィールドの順序を Tuple
反映するオブジェクトのハッシュ コードを返す方法です。 次の例は、 クラスを使用する可能性のある実装を Tuple<T1,T2> 示しています。 ただし、オブジェクトのインスタンス化 Tuple
のパフォーマンス オーバーヘッドは、ハッシュ テーブルに多数のオブジェクトを格納するアプリケーションの全体的なパフォーマンスに大きな影響を与える可能性があることに注意してください。
using System;
public struct Point
{
private int x;
private int y;
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
public override bool Equals(Object obj)
{
if (obj is Point)
{
Point p = (Point) obj;
return x == p.x & y == p.y;
}
else
{
return false;
}
}
public override int GetHashCode()
{
return Tuple.Create(x, y).GetHashCode();
}
}
public class Example
{
public static void Main()
{
Point pt = new Point(5, 8);
Console.WriteLine(pt.GetHashCode());
pt = new Point(8, 5);
Console.WriteLine(pt.GetHashCode());
}
}
// The example displays the following output:
// 173
// 269
[<Struct; CustomEquality; NoComparison>]
type Point(x: int, y: int) =
member _.X = x
member _.Y = y
override _.Equals(obj) =
match obj with
| :? Point as p ->
x = p.X && y = p.Y
| _ ->
false
override _.GetHashCode() =
(x, y).GetHashCode()
let pt = Point(5, 8)
printfn $"{pt.GetHashCode()}"
let pt2 = Point(8, 5)
printfn $"{pt2.GetHashCode()}"
// The example displays the following output:
// 173
// 269
Public Structure Point
Private x As Integer
Private y As Integer
Public Sub New(x As Integer, y As Integer)
Me.x = x
Me.y = y
End Sub
Public Overrides Function Equals(obj As Object) As Boolean
If Not TypeOf obj Is Point Then Return False
Dim p As Point = CType(obj, Point)
Return x = p.x And y = p.y
End Function
Public Overrides Function GetHashCode() As Integer
Return Tuple.Create(x, y).GetHashCode()
End Function
End Structure
Public Module Example
Public Sub Main()
Dim pt As New Point(5, 8)
Console.WriteLine(pt.GetHashCode())
pt = New Point(8, 5)
Console.WriteLine(pt.GetHashCode())
End Sub
End Module
' The example displays the following output:
' 173
' 269
2 つ目の代替ソリューションでは、連続するフィールドのハッシュ コードを 2 ビット以上左シフトして、個々のハッシュ コードに重み付けを行います。 最適には、ビット 31 を超えてシフトされたビットは、破棄されるのではなくラップされます。 ビットは C# と Visual Basic の両方の左シフト演算子によって破棄されるため、次のような左シフトとラップのメソッドを作成する必要があります。
public int ShiftAndWrap(int value, int positions)
{
positions = positions & 0x1F;
// Save the existing bit pattern, but interpret it as an unsigned integer.
uint number = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
// Preserve the bits to be discarded.
uint wrapped = number >> (32 - positions);
// Shift and wrap the discarded bits.
return BitConverter.ToInt32(BitConverter.GetBytes((number << positions) | wrapped), 0);
}
let shiftAndWrap (value: int) positions =
let positions = positions &&& 0x1F
// Save the existing bit pattern, but interpret it as an unsigned integer.
let number = BitConverter.ToUInt32(BitConverter.GetBytes value, 0)
// Preserve the bits to be discarded.
let wrapped = number >>> (32 - positions)
// Shift and wrap the discarded bits.
BitConverter.ToInt32(BitConverter.GetBytes((number <<< positions) ||| wrapped), 0)
Public Function ShiftAndWrap(value As Integer, positions As Integer) As Integer
positions = positions And &h1F
' Save the existing bit pattern, but interpret it as an unsigned integer.
Dim number As UInteger = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0)
' Preserve the bits to be discarded.
Dim wrapped AS UInteger = number >> (32 - positions)
' Shift and wrap the discarded bits.
Return BitConverter.ToInt32(BitConverter.GetBytes((number << positions) Or wrapped), 0)
End Function
次の例では、この shift-and-wrap メソッドを使用して、前の例で使用した Point
構造体のハッシュ コードを計算します。
using System;
public struct Point
{
private int x;
private int y;
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
public override bool Equals(Object obj)
{
if (!(obj is Point)) return false;
Point p = (Point) obj;
return x == p.x & y == p.y;
}
public override int GetHashCode()
{
return ShiftAndWrap(x.GetHashCode(), 2) ^ y.GetHashCode();
}
private int ShiftAndWrap(int value, int positions)
{
positions = positions & 0x1F;
// Save the existing bit pattern, but interpret it as an unsigned integer.
uint number = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
// Preserve the bits to be discarded.
uint wrapped = number >> (32 - positions);
// Shift and wrap the discarded bits.
return BitConverter.ToInt32(BitConverter.GetBytes((number << positions) | wrapped), 0);
}
}
public class Example
{
public static void Main()
{
Point pt = new Point(5, 8);
Console.WriteLine(pt.GetHashCode());
pt = new Point(8, 5);
Console.WriteLine(pt.GetHashCode());
}
}
// The example displays the following output:
// 28
// 37
open System
[<Struct; CustomEquality; NoComparison>]
type Point(x: int, y: int) =
member _.X = x
member _.Y = y
override _.Equals(obj) =
match obj with
| :? Point as p ->
x = p.X && y = p.Y
| _ ->
false
override this.GetHashCode() =
this.ShiftAndWrap(x.GetHashCode(), 2) ^^^ y.GetHashCode()
member _.ShiftAndWrap(value, positions) =
let positions = positions &&& 0x1F
// Save the existing bit pattern, but interpret it as an unsigned integer.
let number = BitConverter.ToUInt32(BitConverter.GetBytes value, 0)
// Preserve the bits to be discarded.
let wrapped = number >>> (32 - positions)
// Shift and wrap the discarded bits.
BitConverter.ToInt32(BitConverter.GetBytes((number <<< positions) ||| wrapped), 0)
let pt = Point(5, 8)
printfn $"{pt.GetHashCode()}"
let pt2 = Point(8, 5)
printfn $"{pt2.GetHashCode()}"
// The example displays the following output:
// 28
// 37
Public Structure Point
Private x As Integer
Private y As Integer
Public Sub New(x As Integer, y As Integer)
Me.x = x
Me.y = y
End Sub
Public Overrides Function Equals(obj As Object) As Boolean
If Not TypeOf obj Is Point Then Return False
Dim p As Point = CType(obj, Point)
Return x = p.x And y = p.y
End Function
Public Overrides Function GetHashCode() As Integer
Return ShiftAndWrap(x.GetHashCode(), 2) XOr y.GetHashCode()
End Function
Private Function ShiftAndWrap(value As Integer, positions As Integer) As Integer
positions = positions And &h1F
' Save the existing bit pattern, but interpret it as an unsigned integer.
Dim number As UInteger = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0)
' Preserve the bits to be discarded.
Dim wrapped AS UInteger = number >> (32 - positions)
' Shift and wrap the discarded bits.
Return BitConverter.ToInt32(BitConverter.GetBytes((number << positions) Or wrapped), 0)
End Function
End Structure
Module Example
Public Sub Main()
Dim pt As New Point(5, 8)
Console.WriteLine(pt.GetHashCode())
pt = New Point(8, 5)
Console.WriteLine(pt.GetHashCode())
End Sub
End Module
' The example displays the following output:
' 28
' 37
注釈
ハッシュ コードは、クラスからDictionaryBase派生した型などのDictionary<TKey,TValue>Hashtableハッシュ ベースのコレクション内のオブジェクトを挿入および識別するために使用される数値です。 メソッドは GetHashCode 、オブジェクトの等価性をすばやくチェックする必要があるアルゴリズムに対して、このハッシュ コードを提供します。
注意
ハッシュ テーブルでのハッシュ コードの使用方法と、いくつかの追加のハッシュ コード アルゴリズムについては、Wikipedia の ハッシュ関数 エントリを参照してください。
等しい 2 つのオブジェクトは、等しいハッシュ コードを返します。 ただし、逆は true ではありません。等しいハッシュ コードは、異なる (等しくない) オブジェクトが同じハッシュ コードを持つ可能性があるため、オブジェクトの等価性を意味しません。 さらに、.NET では メソッドの既定のGetHashCode実装は保証されません。また、このメソッドが返す値は、.NET 実装 (.NET Framework と .NET Core の異なるバージョンなど) と、32 ビットプラットフォームや 64 ビット プラットフォームなどのプラットフォームによって異なる場合があります。 これらの理由から、このメソッドの既定の実装は、ハッシュの目的で一意のオブジェクト識別子として使用しないでください。 次の 2 つの結果が続きます。
等しいハッシュ コードがオブジェクトの等価性を意味するとは想定しないでください。
同じオブジェクトがアプリケーション ドメイン、プロセス、プラットフォーム間でハッシュされる可能性があるため、作成されたアプリケーション ドメインの外部でハッシュ コードを保持したり、使用したりしないでください。
警告
ハッシュ コードは、ハッシュ テーブルに基づくコレクション内での効率的な挿入と参照を目的としています。 ハッシュ コードは永続的な値ではありません。 この理由から、次の操作を行います。
- ハッシュ コード値をシリアル化したり、データベースに格納したりしないでください。
- キー付きコレクションからオブジェクトを取得するキーとしてハッシュ コードを使用しないでください。
- アプリケーション ドメインまたはプロセス間でハッシュ コードを送信しないでください。 場合によっては、ハッシュ コードはプロセスごとまたはアプリケーションごとのドメイン単位で計算される場合があります。
- 暗号的に強力なハッシュが必要な場合は、暗号化ハッシュ関数によって返される値の代わりにハッシュ コードを使用しないでください。 暗号化ハッシュの場合は、 クラスまたは System.Security.Cryptography.KeyedHashAlgorithm クラスから派生したクラスをSystem.Security.Cryptography.HashAlgorithm使用します。
- ハッシュ コードの等価性をテストして、2 つのオブジェクトが等しいかどうかを判断しないでください。 (等しくないオブジェクトは同じハッシュ コードを持つことができます)。等しいかどうかをテストするには、 メソッドまたは Equals メソッドをReferenceEquals呼び出します。
メソッドは GetHashCode 、派生型によってオーバーライドできます。 がオーバーライドされない場合 GetHashCode 、参照型のハッシュ コードは、オブジェクトの参照に基づいてハッシュ コードを計算する基底クラスの メソッドを呼び出 Object.GetHashCode すことによって計算されます。詳細については、「 」を参照してください RuntimeHelpers.GetHashCode。 言い換えると、メソッドが返す ReferenceEqualstrue
2 つのオブジェクトのハッシュ コードは同じです。 値型が をオーバーライド GetHashCodeしない場合、 ValueType.GetHashCode 基底クラスの メソッドはリフレクションを使用して、型のフィールドの値に基づいてハッシュ コードを計算します。 言い換えると、フィールドの値が等しい値を持つ値型のハッシュ コードは等しくなります。 のオーバーライドの GetHashCode詳細については、「継承者へのメモ」セクションを参照してください。
警告
メソッドをオーバーライドする GetHashCode 場合は、 をオーバーライドし、その逆もオーバーライド Equalsする必要があります。 2 つのオブジェクトが等しいかどうかをテストするときにオーバーライド Equals されたメソッドが を返す true
場合、オーバーライドされた GetHashCode メソッドは 2 つのオブジェクトに対して同じ値を返す必要があります。
ハッシュ テーブルのキーとして使用される オブジェクトが の GetHashCode便利な実装を提供しない場合は、クラス コンストラクターのいずれかのオーバーロードに実装を IEqualityComparer 指定することで、ハッシュ コード プロバイダーを Hashtable 指定できます。
Windows ランタイムに関する注意事項
Windows ランタイムの GetHashCode クラスで メソッドを呼び出すと、 をオーバーライドGetHashCodeしないクラスの既定の動作が提供されます。 これは、.NET FrameworkがWindows ランタイムに提供するサポートの一部です (「Windows ストア アプリとWindows ランタイムのサポート.NET Framework」を参照してください)。 Windows ランタイムのクラスは を継承Objectせず、現在は をGetHashCode実装していません。 ただし、C# または Visual Basic コードで使用すると、メソッド 、、および GetHashCode メソッドが表示ToStringEquals(Object)され、.NET Frameworkによってこれらのメソッドの既定の動作が提供されます。
注意
C# または Visual Basic で記述されたWindows ランタイムクラスは、 メソッドをGetHashCodeオーバーライドできます。
注意 (継承者)
ハッシュ関数は、オブジェクトの値に対応する数値 (ハッシュ コード) をすばやく生成するために使用されます。 ハッシュ関数は通常、各型に固有であり、一意性のために、少なくとも 1 つのインスタンス フィールドを入力として使用する必要があります。 ハッシュ コードは、静的フィールドの値を使用して計算しないでください。
から Object派生したクラスの場合、 GetHashCode
派生クラス GetHashCode() が参照の等価性として等しいと定義されている場合にのみ、 メソッドは基底クラスの実装にデリゲートできます。 参照型の の既定の GetHashCode() 実装では、 メソッドによって返されるハッシュ コードと同等のハッシュ コードが GetHashCode(Object) 返されます。 変更できない参照型の場合は、 をオーバーライド GetHashCode() できます。 一般に、変更可能な参照型の場合は、次の場合にのみオーバーライド GetHashCode() する必要があります。
変更できないフィールドからハッシュ コードを計算できます。または
オブジェクトがハッシュ コードに依存するコレクションに含まれている間、変更可能なオブジェクトのハッシュ コードが変更されないようにすることができます。
そうしないと、変更可能なオブジェクトがハッシュ テーブルで失われたと考える場合があります。 変更可能な参照型のオーバーライド GetHashCode() を選択した場合、ドキュメントでは、オブジェクトがハッシュ テーブルに格納されている間、型のユーザーがオブジェクトの値を変更しないことを明確にする必要があります。
値型の場合、 GetHashCode() はリフレクションを使用する既定のハッシュ コード実装を提供します。 パフォーマンスを向上させるには、オーバーライドすることを検討する必要があります。
ハッシュ コードをさまざまな方法で計算する詳細と例については、「例」セクションを参照してください。
ハッシュ関数には、次のプロパティが必要です。
2 つのオブジェクトが等しいと比較する場合、各オブジェクトの GetHashCode() メソッドは同じ値を返す必要があります。 ただし、2 つのオブジェクトが等しいと比較されない場合、 GetHashCode() 2 つのオブジェクトのメソッドは異なる値を返す必要はありません。
オブジェクトのメソッドは GetHashCode() 、オブジェクトの System.Object.Equals メソッドの戻り値を決定するオブジェクトの状態に変更がない限り、同じハッシュ コードを一貫して返す必要があります。 これは、アプリケーションの現在の実行に対してのみ当てはまります。また、アプリケーションを再度実行した場合は、別のハッシュ コードを返すことができます。
最適なパフォーマンスを得るには、ハッシュ関数は、大量にクラスター化された入力を含むすべての入力に対して偶数分布を生成する必要があります。 つまり、オブジェクトの状態を小さく変更すると、結果として得られるハッシュ コードが大きく変更され、最適なハッシュ テーブルのパフォーマンスが得られます。
ハッシュ関数は、計算に安価である必要があります。
メソッドは例外を GetHashCode() スローしないでください。
たとえば、 クラスによって提供される メソッドの GetHashCode() 実装では String 、同じ文字列値に対して同じハッシュ コードが返されます。 したがって、2 つの String オブジェクトが同じ文字列値を表す場合、同じハッシュ コードを返します。 また、 メソッドは文字列内のすべての文字を使用して、入力が特定の範囲にクラスター化されている場合でも、合理的にランダムに分散された出力を生成します (たとえば、文字列には 65,535 個の Unicode 文字のいずれかを含めることができる場合でも、下位 128 文字の ASCII 文字のみを含む文字列が多い場合があります)。
クラスに適切なハッシュ関数を提供すると、それらのオブジェクトをハッシュ テーブルに追加するパフォーマンスに大きく影響する可能性があります。 ハッシュ関数の適切な実装を提供するキーを持つハッシュ テーブルでは、要素の検索には一定の時間がかかります (たとえば、O(1) 操作)。 ハッシュ関数の実装が不適切なハッシュ テーブルでは、検索のパフォーマンスは、ハッシュ テーブル内の項目の数 (O(n
) 操作などによって異なります。ここで n
、 はハッシュ テーブル内の項目の数です)。 悪意のあるユーザーは、競合の数を増やすデータを入力する可能性があります。これにより、次の条件下で、ハッシュ テーブルに依存するアプリケーションのパフォーマンスが大幅に低下する可能性があります。
ハッシュ関数によって頻繁に競合が発生する場合。
ハッシュ テーブル内のオブジェクトの大部分が、互いに等しいかほぼ等しいハッシュ コードを生成する場合。
ユーザーがハッシュ コードの計算元のデータを入力したとき。
等しいと見なされる 2 つのオブジェクトが同じハッシュ コードを持っていることを保証するために、 をオーバーライド GetHashCode() する派生クラスもオーバーライド Equals(Object) する必要があります。それ以外の場合は、型が Hashtable 正しく動作しない可能性があります。