System.Object.GetHashCode 메서드

이 문서에서는 이 API에 대한 참조 설명서에 대한 추가 설명서를 제공합니다.

이 메서드는 GetHashCode 개체 같음의 빠른 검사 필요한 알고리즘에 대한 해시 코드를 제공합니다. 해시 코드는 클래스, Hashtable 클래스 또는 클래스에서 파생된 형식과 같은 Dictionary<TKey,TValue> 해시 기반 컬렉션에서 DictionaryBase 개체를 삽입하고 식별하는 데 사용되는 숫자 값입니다.

참고 항목

해시 테이블에서 해시 코드를 사용하는 방법과 몇 가지 추가 해시 코드 알고리즘에 대한 자세한 내용은 Wikipedia의 해시 함수 항목을 참조하세요.

동일한 반환 해시 코드인 두 개체입니다. 그러나 반대는 true가 아닙니다. 다른(같지 않은) 개체에는 동일한 해시 코드가 있을 수 있기 때문에 동일한 해시 코드가 개체 같음을 의미하지는 않습니다. 또한 .NET은 메서드의 GetHashCode 기본 구현을 보장하지 않으며, 이 메서드가 반환하는 값은 .NET Framework 및 .NET Core의 다른 버전과 같은 .NET 구현과 32비트 및 64비트 플랫폼과 같은 플랫폼 간에 다를 수 있습니다. 이러한 이유로 이 메서드의 기본 구현을 해시 용도로 고유한 개체 식별자로 사용하지 마세요. 두 가지 결과는 다음과 같습니다.

  • 동일한 해시 코드가 개체 같음을 암시한다고 가정해서는 안 됩니다.
  • 되지 유지 하거나 애플리케이션 도메인, 프로세스 및 플랫폼에서 동일한 개체 해시 수 때문에 생성 된 애플리케이션 도메인 외부 해시 코드를 사용 해야 합니다.

Warning

해시 코드는 해시 테이블을 기반으로 하는 컬렉션에서 효율적인 삽입 및 조회를 위한 것입니다. 해시 코드는 영구 값이 아닙니다. 이러한 이유로:

  • 해시 코드 값을 직렬화하거나 데이터베이스에 저장하지 마세요.
  • 키 컬렉션에서 개체를 검색하는 키로 해시 코드를 사용하지 마세요.
  • 애플리케이션 도메인 또는 프로세스에서 해시 코드를 보내지 않습니다. 경우에 따라 해시 코드는 프로세스별로 계산되거나 애플리케이션별로 계산될 수 있습니다기본.
  • 암호화에 강력한 해시가 필요한 경우 암호화 해시 함수에서 반환하는 값 대신 해시 코드를 사용하지 마세요. 암호화 해시의 경우 또는 System.Security.Cryptography.KeyedHashAlgorithm 클래스에서 파생된 클래스를 System.Security.Cryptography.HashAlgorithm 사용합니다.
  • 두 개체가 같은지 여부를 확인하기 위해 해시 코드의 같음을 테스트하지 마세요. (같지 않은 개체는 동일한 해시 코드를 가질 수 있습니다.) 같음을 테스트하려면 또는 Equals 메서드를 호출합니다ReferenceEquals.

메서드는 GetHashCode 파생된 형식으로 재정의할 수 있습니다. 재정의되지 않은 경우 GetHashCode 참조 형식에 대한 해시 코드는 개체의 참조를 기반으로 해시 코드를 계산하는 기본 클래스의 메서드를 호출 Object.GetHashCode 하여 계산됩니다. 자세한 내용은 다음을 참조하세요 RuntimeHelpers.GetHashCode. 즉, 메서드가 반환 true 하는 두 개체에는 ReferenceEquals 동일한 해시 코드가 있습니다. 값 형식이 재정 GetHashCodeValueType.GetHashCode 의되지 않는 경우 기본 클래스의 메서드는 리플렉션을 사용하여 형식 필드의 값을 기반으로 해시 코드를 계산합니다. 즉, 필드 값이 같은 값이 있는 값 형식에는 해시 코드가 같습니다. 재정 GetHashCode의에 대한 자세한 내용은 "상속자에 대한 참고 사항" 섹션을 참조하세요.

Warning

메서드를 재정의하는 경우 재정EqualsGetHashCode 해야 하며 그 반대의 경우도 마찬가지입니다. 두 개체가 같은지 테스트할 때 재정 Equals 의된 메서드가 반환 true 되는 경우 재정의된 GetHashCode 메서드는 두 개체에 대해 동일한 값을 반환해야 합니다.

해시 테이블에서 키로 사용되는 개체가 유용한 구현GetHashCode을 제공하지 않는 경우 클래스 생성자의 오버로드 Hashtable 중 하나에 구현을 IEqualityComparer 제공하여 해시 코드 공급자를 지정할 수 있습니다.

Windows 런타임 대한 참고 사항

Windows 런타임 클래스에서 메서드를 호출 GetHashCode 할 때 재정GetHashCode의하지 않는 클래스에 대한 기본 동작을 제공합니다. 이 기능은 .NET이 Windows 런타임 대해 제공하는 지원의 일부입니다(Windows 스토어 앱 및 Windows 런타임 .NET 지원 참조). Windows 런타임 클래스는 상속Object되지 않으며 현재는 구현GetHashCode하지 않습니다. 그러나 C# 또는 Visual Basic 코드에서 사용할 때 메서드와 GetHashCode 메서드가 있는 것처럼 보이며 ToStringEquals(Object).NET Framework는 이러한 메서드에 대한 기본 동작을 제공합니다.

참고 항목

C# 또는 Visual Basic으로 작성된 Windows 런타임 클래스는 메서드를 재정의할 GetHashCode 수 있습니다.

예제

형식과 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 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

형식에는 해시 코드 생성에 참여할 수 있는 여러 데이터 필드가 있는 경우가 많습니다. 해시 코드를 생성하는 한 가지 방법은 다음 예제와 같이 작업을 사용하여 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 $"{pt.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)에 대해 동일한 해시 코드를 반환하므로 바람직한 것보다 더 많은 충돌이 발생할 수 있습니다. 이러한 경우 해시 코드가 동일하지 않도록 다양한 솔루션을 사용할 수 있습니다. 하나는 각 필드의 순서를 Tuple 반영하는 개체의 해시 코드를 반환하는 것입니다. 다음 예제에서는 클래스를 사용 하는 가능한 구현을 보여 주세요 Tuple<T1,T2> . 단는 인스턴스화하는 성능 오버 헤드를 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 Tuple.Create(x, y).GetHashCode();
    }
}

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 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

두 번째 대안 솔루션에는 연속 필드의 해시 코드를 두 비트 이상 왼쪽으로 이동하여 개별 해시 코드의 가중치를 지정하는 작업이 포함됩니다. 최적으로 비트 31 이상으로 이동한 비트는 dis카드ed가 아닌 래핑되어야 합니다. 비트는 C# 및 Visual Basic의 왼쪽 시프트 연산자에서 카드 해제되므로 다음과 같이 왼쪽 shift-and-wrap 메서드를 만들어야 합니다.

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 Example2
{
   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 Point5
    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 Point5 Then Return False

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

        pt = New Point5(8, 5)
        Console.WriteLine(pt.GetHashCode())
    End Sub
End Module
' The example displays the following output:
'       28
'       37