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 つは、単にその値を Int32 返す方法です。 次の例は、 構造体のこのような実装を示 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
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.
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
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);
}
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

次の例では、このシフトアンドラップ メソッドを使用して、前の例で使用した構造体のハッシュ コード 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
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

注釈

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

注意

ハッシュ テーブルでハッシュ コードがどのように使用されるのか、およびいくつかの追加のハッシュ コード アルゴリズムについては、Wikipedia のハッシュ関数 エントリを参照 してください。

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

  • 等しいハッシュ コードがオブジェクトの等値を示す場合は想定すべきではありません。

  • 同じオブジェクトがアプリケーション ドメイン、プロセス、およびプラットフォーム間でハッシュされる可能性があるため、作成されたアプリケーション ドメインの外部でハッシュ コードを永続化したり使用したりすることはできません。

警告

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

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

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

警告

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

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

Windows ランタイムに関する注意事項

Windows Runtime のクラスで メソッドを呼び出す場合、 をオーバーライドしないクラスの既定の動作 GetHashCode が提供されます GetHashCode 。 これは、.NET Framework が Windows ランタイムに提供するサポートの一部です (「Windows Store Windows Apps と Windows ランタイムの .NET Framework サポート」を参照してください)。 ランタイムのクラスWindows継承されません。 Object 現在、 は実装されません GetHashCode 。 ただし ToString Equals(Object) 、C# または Visual Basic コードで使用すると、および メソッドが含み、.NET Framework によってこれらのメソッドの既定の動作が提供されます GetHashCode

注意

WindowsC# または C# で記述されたランタイム クラスは、Visual Basicオーバーライド GetHashCode できます。

注意 (継承者)

ハッシュ関数は、オブジェクトの値に対応する数値 (ハッシュ コード) をすばやく生成するために使用されます。 ハッシュ関数は通常、各型に固有であり、一意性を高めていく場合は、少なくとも 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 オブジェクトが同じ文字列値を表す場合、2 つのオブジェクトは同じハッシュ コードを返します。 また、 メソッドは、入力が特定の範囲でクラスター化されている場合でも、文字列内のすべての文字を使用して、ランダムに分散された出力を生成します (たとえば、多くのユーザーは、文字列に 65,535 文字の Unicode 文字を含めることができますが、より小さい 128 ASCII 文字のみを含む文字列を持つ場合があります)。

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

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

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

  • ユーザーがハッシュ コードの計算に使用するデータを入力した場合。

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

適用対象

こちらもご覧ください