[C#] .NET의 IEqualityComparer <T>에서 GetHashCode의 역할은 무엇입니까?
IEqualityComparer 인터페이스의 GetHashCode 메서드 역할을 이해하려고합니다.
다음 예제는 MSDN에서 가져 왔습니다.
using System;
using System.Collections.Generic;
class Example {
static void Main() {
try {
BoxEqualityComparer boxEqC = new BoxEqualityComparer();
Dictionary<Box, String> boxes = new Dictionary<Box,
string>(boxEqC);
Box redBox = new Box(4, 3, 4);
Box blueBox = new Box(4, 3, 4);
boxes.Add(redBox, "red");
boxes.Add(blueBox, "blue");
Console.WriteLine(redBox.GetHashCode());
Console.WriteLine(blueBox.GetHashCode());
}
catch (ArgumentException argEx) {
Console.WriteLine(argEx.Message);
}
}
}
public class Box {
public Box(int h, int l, int w) {
this.Height = h;
this.Length = l;
this.Width = w;
}
public int Height { get; set; }
public int Length { get; set; }
public int Width { get; set; }
}
class BoxEqualityComparer : IEqualityComparer<Box> {
public bool Equals(Box b1, Box b2) {
if (b1.Height == b2.Height & b1.Length == b2.Length
& b1.Width == b2.Width) {
return true;
}
else {
return false;
}
}
public int GetHashCode(Box bx) {
int hCode = bx.Height ^ bx.Length ^ bx.Width;
return hCode.GetHashCode();
}
}
Equals 메소드 구현이 두 개의 Box 객체를 비교하기에 충분하지 않아야합니까? 그것이 우리가 프레임 워크에게 객체를 비교하는데 사용 된 규칙을 알려주는 곳입니다. GetHashCode가 필요한 이유는 무엇입니까?
감사.
루시안
답변
먼저 약간의 배경 …
.NET의 모든 개체에는 Equals 메서드와 GetHashCode 메서드가 있습니다.
Equals 메서드는 한 개체를 다른 개체와 비교하는 데 사용됩니다. 두 개체가 같은지 확인합니다.
GetHashCode 메서드는 개체의 32 비트 정수 표현을 생성합니다. 개체에 포함 할 수있는 정보의 양에는 제한이 없으므로 특정 해시 코드는 여러 개체에서 공유되므로 해시 코드가 반드시 고유하지는 않습니다.
딕셔너리는 추가 / 제거 / 가져 오기 작업에 대한 일정한 비용을 대가로 더 높은 메모리 풋 프린트를 거래하는 정말 멋진 데이터 구조입니다. 그래도 반복하기에는 좋지 않은 선택입니다. 내부적으로 사전에는 값을 저장할 수있는 버킷 배열이 포함되어 있습니다. 키와 값을 사전에 추가하면 키에서 GetHashCode 메서드가 호출됩니다. 반환 된 해시 코드는 키 / 값 쌍을 저장해야하는 버킷의 인덱스를 결정하는 데 사용됩니다.
값에 액세스하려면 키를 다시 전달하십시오. GetHashCode 메서드는 Key에서 호출되며 Value가 포함 된 버킷이 있습니다.
IEqualityComparer가 사전 생성자에 전달되면 Key 객체의 메서드 대신 IEqualityComparer.Equals 및 IEqualityComparer.GetHashCode 메서드가 사용됩니다.
이제 두 방법이 모두 필요한 이유를 설명하려면 다음 예를 고려하십시오.
BoxEqualityComparer boxEqC = new BoxEqualityComparer();
Dictionary<Box, String> boxes = new Dictionary<Box, string>(boxEqC);
Box redBox = new Box(100, 100, 25);
Box blueBox = new Box(1000, 1000, 25);
boxes.Add(redBox, "red");
boxes.Add(blueBox, "blue");
예제에서 BoxEqualityComparer.GetHashCode 메소드를 사용하면 두 상자 모두 동일한 해시 코드 (100 ^ 100 ^ 25 = 1000 ^ 1000 ^ 25 = 25)를 갖지만 분명히 동일한 객체는 아닙니다. 이 경우에 동일한 해시 코드 인 이유는 ^ (비트 배타적 OR) 연산자를 사용하고 있기 때문에 100 ^ 100은 1000 ^ 1000과 마찬가지로 0을 남기지 않고 취소하기 때문입니다. 서로 다른 두 객체에 동일한 키가 있으면 충돌이라고합니다.
동일한 해시 코드를 가진 두 개의 키 / 값 쌍을 사전에 추가하면 둘 다 동일한 버킷에 저장됩니다. 따라서 Value를 검색하려면 키에서 GetHashCode 메서드가 호출되어 버킷을 찾습니다. 버킷에 둘 이상의 값이 있으므로 사전에서 버킷의 모든 키 / 값 쌍을 반복하여 키에서 Equals 메서드를 호출하여 올바른 값을 찾습니다.
게시 한 예에서 두 상자는 동일하므로 Equals 메서드는 true를 반환합니다. 이 경우 사전에는 두 개의 동일한 키가 있으므로 예외가 발생합니다.
TLDR
요약하면 GetHashCode 메서드는 개체가 저장된 주소를 생성하는 데 사용됩니다. 따라서 사전은 검색 할 필요가 없습니다. 해시 코드를 계산하고 해당 위치로 이동합니다. Equals 방법은 더 나은 평등 테스트이지만 개체를 주소 공간에 매핑하는 데 사용할 수 없습니다.
답변
GetHashCode 는 Dictionary 사전에 사용되며 개체를 저장하기위한 해시를 만듭니다. 다음은 IEqualtyComparer 및 GetHashCode 를 사용하는 이유와 방법에 대한 유용한 기사입니다. http://dotnetperls.com/iequalitycomparer
답변
a 및 Dictionary<TKey,TValue>
그것의 GetValue
유사한 메소드가 Equals
저장된 모든 단일 키를 호출 하여 원하는 키와 일치하는지 확인할 수는 있지만 매우 느릴 것입니다. 대신, 많은 해시 기반 컬렉션과 마찬가지로 GetHashCode
일치하지 않는 대부분의 값을 고려 대상에서 빠르게 제외 해야합니다 . GetHashCode
찾는 아이템을 호출 하면 42가 생성되고 컬렉션에 53,917 개의 아이템이 있지만 GetHashCode
53,914를 호출 하면 42 이외의 값이 생성되면 찾는 아이템과 비교할 때 3 개의 아이템 만 비교하면됩니다. 다른 53,914는 무시해도됩니다.
a GetHashCode
가 포함 되는 이유는 IEqualityComparer<T>
사전 소비자가 일반적으로 서로를 동일하게 간주 하지 않는 동일한 객체로 간주하기를 원할 수 있기 때문입니다 . 가장 일반적인 예는 문자열을 키로 사용하지만 대 / 소문자를 구분하지 않는 호출자입니다. 이 작업을 효율적으로 수행하려면 사전에 “Fox”및 “FOX”에 대해 동일한 값을 생성하지만 “box”또는 “zebra”에 대해 다른 값을 생성하는 해시 함수 형식이 필요합니다. 이후 GetHashCode
에 내장 된 방법은 String
그런 식으로 작동하지 않습니다, 사전이 다른 곳에서 이러한 방법을 얻을 필요가있을 것이다,IEqualityComparer<T>
Equals
“Fox”와 “FOX”는 서로 동일하지만 “box”또는 “zebra”는 동일하지 않은 방법입니다.