Object.GetHashCode メソッド

定義

既定のハッシュ関数として機能します。

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 Example1
{
   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 Example1
    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 Point2
{
    private int x;
    private int y;

    public Point2(int x, int y)
    {
       this.x = x;
       this.y = y;
    }

    public override bool Equals(Object obj)
    {
       if (! (obj is Point2)) return false;

       Point2 p = (Point2) obj;
       return x == p.x & y == p.y;
    }

    public override int GetHashCode()
    {
        return x ^ y;
    }
}

public class Example3
{
   public static void Main()
   {
      Point2 pt = new Point2(5, 8);
      Console.WriteLine(pt.GetHashCode());

      pt = new Point2(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 $"{pt2.GetHashCode()}"

// The example displays the following output:
//       13
//       13
' A type that represents a 2-D point.
Public Structure Point3
    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 Point3 Then Return False

        Dim p As Point3 = CType(obj, Point3)
        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 Example3
    Public Sub Main()
        Dim pt As New Point3(5, 8)
        Console.WriteLine(pt.GetHashCode())

        pt = New Point3(8, 5)
        Console.WriteLine(pt.GetHashCode())
    End Sub
End Module

前の例では、(n1、n2) と (n2、n1) に同じハッシュ コードが返されるため、望ましいよりも多くの競合が発生する可能性があります。 .NET 5 以降では、 HashCode.Combineを使用することをお勧めします。 対称性の問題を回避し、 Tuple オブジェクトを作成するオーバーヘッドなしで適切に分散されたハッシュ コードを生成します。

using System;

public struct Point3
{
    private int x;
    private int y;

    public Point3(int x, int y)
    {
       this.x = x;
       this.y = y;
    }

    public override bool Equals(Object obj)
    {
        if (obj is Point3)
        {
            Point3 p = (Point3) obj;
            return x == p.x & y == p.y;
        }
        else
        {
            return false;
        }      
    }

    public override int GetHashCode()
    {
        return HashCode.Combine(x, y);
    }
}

public class Example
{
   public static void Main()
   {
        Point3 pt = new Point3(5, 8);
        Console.WriteLine(pt.GetHashCode());

        pt = new Point3(8, 5);
        Console.WriteLine(pt.GetHashCode());
   }
}
// The example displays output similar to the following.
// Note: HashCode.Combine results are not stable across .NET versions.
//       185727722
//       -363254492
[<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() =
        System.HashCode.Combine(x, y)

let pt = Point(5, 8)
printfn $"{pt.GetHashCode()}"

let pt2 = Point(8, 5)
printfn $"{pt2.GetHashCode()}"
// The example displays output similar to the following.
// Note: HashCode.Combine results are not stable across .NET versions.
//       185727722
//       -363254492
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 HashCode.Combine(x, 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         
' The example displays output similar to the following.
' Note: HashCode.Combine results are not stable across .NET versions.
'       185727722
'       -363254492

注釈

GetHashCode メソッドは、オブジェクトの等価性をすばやくチェックする必要があるアルゴリズムのハッシュ コードを提供します。 ハッシュ コードは、 Dictionary<TKey,TValue> クラス、 Hashtable クラス、 DictionaryBase クラスから派生した型など、ハッシュ ベースのコレクション内のオブジェクトを挿入および識別するために使用される数値です。

Note

ハッシュ テーブルでハッシュ コードを使用する方法と、いくつかの追加のハッシュ コード アルゴリズムについては、Wikipedia の ハッシュ関数 エントリを参照してください。

等しい 2 つのオブジェクトは、等しいハッシュ コードを返します。 ただし、逆は正しくありません。等しいハッシュ コードは、異なる (等しくない) オブジェクトが同じハッシュ コードを持つ可能性があるため、オブジェクトの等価性を意味しません。 さらに、.NETでは、GetHashCode メソッドの既定の実装は保証されません。また、このメソッドが返す値は、.NETの実装とプラットフォーム (32 ビットと 64 ビットのプラットフォームの間など) によって異なる場合があります。 このような理由から、このメソッドの既定の実装は、ハッシュの目的で一意のオブジェクト識別子として使用しないでください。 その結果、次の 2 つの結果が得まれます。

  • 等しいハッシュ コードがオブジェクトの等価性を意味するとは想定しないでください。
  • 同じオブジェクトがアプリケーション ドメイン、プロセス、プラットフォーム間でハッシュされる可能性があるため、作成されたアプリケーション ドメインの外部でハッシュ コードを保持したり使用したりしないでください。

Warning

ハッシュ コードは、ハッシュ テーブルに基づくコレクション内での効率的な挿入と検索を目的としています。 ハッシュ コードは永続的な値ではありません。 このため、次のことが行われます。

  • ハッシュ コード値をシリアル化したり、データベースに格納したりしないでください。
  • キー付きコレクションからオブジェクトを取得するキーとしてハッシュ コードを使用しないでください。
  • アプリケーション ドメインまたはプロセス間でハッシュ コードを送信しないでください。 場合によっては、ハッシュ コードがプロセスごとまたはアプリケーション ドメインごとに計算される場合があります。
  • 暗号的に強力なハッシュが必要な場合は、暗号化ハッシュ関数によって返される値の代わりにハッシュ コードを使用しないでください。 暗号化ハッシュの場合は、 System.Security.Cryptography.HashAlgorithm または System.Security.Cryptography.KeyedHashAlgorithm クラスから派生したクラスを使用します。
  • ハッシュ コードの等価性をテストして、2 つのオブジェクトが等しいかどうかを判断しないでください。 (等しくないオブジェクトは同じハッシュ コードを持つことができます)。等しいかどうかをテストするには、 ReferenceEquals メソッドまたは Equals メソッドを呼び出します。

GetHashCode メソッドは、派生型によってオーバーライドできます。 GetHashCodeがオーバーライドされない場合、参照型のハッシュ コードは、オブジェクトの参照に基づいてハッシュ コードを計算する基底クラスのObject.GetHashCode メソッドを呼び出すことによって計算されます。詳細については、RuntimeHelpers.GetHashCodeを参照してください。 つまり、 ReferenceEquals メソッドが返す 2 つのオブジェクト true 同じハッシュ コードを持ちます。 値型が GetHashCodeをオーバーライドしない場合、基底クラスの ValueType.GetHashCode メソッドはリフレクションを使用して、型のフィールドの値に基づいてハッシュ コードを計算します。 言い換えると、フィールドの値が等しい値を持つ値型は、等しいハッシュ コードを持ちます。 GetHashCodeのオーバーライドの詳細については、「継承元へのメモ」セクションを参照してください。

Warning

GetHashCode メソッドをオーバーライドする場合は、Equalsもオーバーライドする必要があります。その逆も同様です。 2 つのオブジェクトが等しいかどうかをテストしたときにオーバーライドされた Equals メソッドが true を返す場合、オーバーライドされた GetHashCode メソッドは、2 つのオブジェクトに対して同じ値を返す必要があります。

ハッシュ テーブルのキーとして使用されるオブジェクトがGetHashCodeの便利な実装を提供しない場合は、IEqualityComparer クラス コンストラクターのいずれかのオーバーロードにHashtable実装を指定することで、ハッシュ コード プロバイダーを指定できます。

注意 (継承者)

ハッシュ関数は、オブジェクトの値に対応する数値 (ハッシュ コード) をすばやく生成するために使用されます。 ハッシュ関数は通常、各型に固有であり、一意性のために、少なくとも 1 つのインスタンス フィールドを入力として使用する必要があります。 ハッシュ コードは、静的フィールドの値を使用して計算しないでください。

Objectから派生したクラスの場合、GetHashCode メソッドは、派生クラスが等価性を参照等価として定義している場合にのみ、基底クラスGetHashCode()実装にデリゲートできます。 参照型の GetHashCode() の既定の実装では、 GetHashCode(Object) メソッドから返されたものと同等のハッシュ コードが返されます。 変更できない参照型の GetHashCode() をオーバーライドできます。 一般に、変更可能な参照型の場合は、次の場合にのみ GetHashCode() をオーバーライドする必要があります。

  • 変更できないフィールドからハッシュ コードを計算できます。または

  • オブジェクトがハッシュ コードに依存するコレクションに含まれている間、変更可能なオブジェクトのハッシュ コードが変更されないようにすることができます。

そうしないと、変更可能なオブジェクトがハッシュ テーブルで失われると考えられる場合があります。 変更可能な参照型の GetHashCode() をオーバーライドする場合、ドキュメントでは、オブジェクトがハッシュ テーブルに格納されている間、型のユーザーがオブジェクト値を変更しないことを明確にする必要があります。

値型の場合、 GetHashCode() はリフレクションを使用する既定のハッシュ コード実装を提供します。 パフォーマンスを向上させるには、オーバーライドすることを検討する必要があります。

ハッシュ コードをさまざまな方法で計算する詳細と例については、「例」セクションを参照してください。

ハッシュ関数には、次のプロパティが必要です。

  • 2 つのオブジェクトが等しいと比較される場合、各オブジェクトの GetHashCode() メソッドは同じ値を返す必要があります。 ただし、2 つのオブジェクトが等しいと比較されない場合、2 つのオブジェクトの GetHashCode() メソッドは異なる値を返す必要はありません。

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

  • 最適なパフォーマンスを得るためのハッシュ関数は、クラスター化が多い入力を含むすべての入力に対して偶数分布を生成する必要があります。 つまり、オブジェクトの状態を小さく変更すると、結果として得られるハッシュ コードが大きく変更され、最適なハッシュ テーブルのパフォーマンスが得られます。

  • ハッシュ関数は計算に安価である必要があります。

  • GetHashCode() メソッドは例外をスローしないでください。

たとえば、GetHashCode() クラスによって提供されるString メソッドの実装では、同じ文字列値に対して同じハッシュ コードが返されます。 したがって、2 つの String オブジェクトが同じ文字列値を表す場合、同じハッシュ コードが返されます。 また、このメソッドでは、文字列内のすべての文字を使用して、入力が特定の範囲にクラスター化されている場合でも、合理的にランダムに分散された出力を生成します (たとえば、文字列に含めることができる Unicode 文字が 65,535 文字であっても、多くのユーザーが下位 128 文字の ASCII 文字のみを含む文字列を持っている場合があります)。

クラスに適切なハッシュ関数を指定すると、それらのオブジェクトをハッシュ テーブルに追加するパフォーマンスに大きく影響する可能性があります。 ハッシュ関数の適切な実装を提供するキーを持つハッシュ テーブルでは、要素の検索に一定の時間がかかります (たとえば、O(1) 操作)。 ハッシュ関数の実装が不十分なハッシュ テーブルでは、検索のパフォーマンスはハッシュ テーブル内の項目の数によって異なります (たとえば、O(n) 操作では、 n はハッシュ テーブル内の項目の数です)。 悪意のあるユーザーは、競合の数を増やすデータを入力できます。これは、次の条件下で、ハッシュ テーブルに依存するアプリケーションのパフォーマンスを大幅に低下させる可能性があります。

  • ハッシュ関数によって頻繁に競合が発生する場合。

  • ハッシュ テーブル内のオブジェクトの大部分が、互いに等しいかほぼ等しいハッシュ コードを生成する場合。

  • ユーザーがハッシュ コードの計算元のデータを入力したとき。

また、 GetHashCode() をオーバーライドする派生クラスは、等しいと見なされる 2 つのオブジェクトが同じハッシュ コードを持っていることを保証するために、 Equals(Object) をオーバーライドする必要があります。それ以外の場合は、 Hashtable 型が正しく動作しない可能性があります。

適用対象

こちらもご覧ください