방프리

23.01.23 Chapter1. 데이터 타입 (Item 10) 본문

C#/More Effective C#

23.01.23 Chapter1. 데이터 타입 (Item 10)

방프리 2023. 1. 23. 14:39

Item 10 : GetHashCode()의 위험성을 이해하라

 

GetHashCode()는 해시 기반 컬렉션에서 키의 해시값을 정의할 때에만 사용된다.

HashCode는 변경 불가능한 값(Database의 Primary Key라 생각하면 쉬울 것 같다.)을 사용해야 하나, 제일 좋은 방법은

GetHashCode() 자체를 사용하지 않는 것이다.

하지만 부득이하게 사용해야할 경우 다음 세 가지 규칙을 따라 사용하는 것이 좋다.

1. 두 객체가 같다면(Equals() 인스턴스 메서드로 비교 시) 동일한 해시값을 생성해야 한다.
   그렇지 않으면 컬렉션에서 객체를 찾는 데 해시 코드를 사용할 수 없다.
   
2. 모든 객체 a에 대해 a.GetHashCode()는 인스턴스 불변이어야 한다. 
   a의 어떤 메서등를 호출하였든 a.GetHashCode()는 항상 같은 값을 반환해야 한다. 
   그래야 객체가 올바른 버킷에 담겨 있다는 것을 보장할 수 있다.

3. 해시 함수는 자주 사용되는 입력값들에 대해서 균일하게 분포된 정숫값을 생성해야 한다. 
   이상적으로라면 값이 널리 분포되어야 하며, 특정 값 주위로 비슷한 값이 여러 번 반환되어서는 안 된다. 
   그래야 컬렉션의 효율이 높아진다. 쉽게 말하자면 각 버킷에적은 수의 객체만 담을 수 있다.

클래스에서 객체의 동등성 비교를 위한 Equals() 함수를 재정의 하는 경우도 있다. 이 때 첫 번째 규칙을 어기지 않기 위해 

GetHashCode() 함수를 반드시 재정의 해야한다. 그렇지 않으면 모든 객체가 같은 HashCode값을 주기 때문이다.

(필자는 string 데이터타입인 Name의 변수의 HashCode()를 통해 변경 불가능한 값으로 사용하고 있다. 개인적인 생각으로는 string이 아닌 Unique 데이터인 int로 해야되지 않을까 싶다. 애초에 변경 불가능한 타입이라고 명시하고 변경이 가능한 데이터로 GetHashCode()를 뽑아내는 것이 좀처럼 이해되지 않는다.)

 

Comments