2011-05-12 3 views
9

사용자 지정 클래스 인스턴스 비교를 구현할 때 EqualsGetHashCode 속성을 모두 재정의해야합니까?개체를 비교할 때 같음 vs GetHashCode

다음 코드에는 클래스 모음이 있습니다. 클래스 AID, 클래스 B- Code으로 비교됩니다.

using System; 
using System.Collections.Generic; 
using System.Diagnostics; 
using System.Linq; 

namespace ConsoleApplication2 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      List<I> bars = new List<I>(); 
      bars.Add(new A() { Id = 1, Code = "one A" }); 
      bars.Add(new B() { Id = 1, Code = "one B" }); 
      bars.Add(new A() { Id = 1, Code = "one A+" }); 
      bars.Add(new B() { Id = 1, Code = "one B" }); // Code = "one B+" 

      var distictBars = bars.Distinct(); 

      foreach (var item in distictBars) 
      { 
       Debug.WriteLine(item.Code); 
      } 
     } 
    } 

    interface I 
    { 
     string Code { get; set; } 
    } 

    class A : I, IEquatable<A> 
    { 
     public int Id { get; set; } 
     public string Code { get; set; } 

     public bool Equals(A other) 
     { 
      // this is the ??? comparison 
      return this.Id == other.Id; 
      //return this.Code == other.Code; 
     } 

     public override bool Equals(object obj) 
     { 
      if (obj is A) 
       return this.Equals(obj as A); 
      else 
       return object.ReferenceEquals(this, obj); 
     } 

     public override int GetHashCode() 
     { 
      // this is the wanted comparison 
      return this.Id; 
     } 
    } 

    class B : I, IEquatable<B> 
    { 
     public int Id { get; set; } 
     public string Code { get; set; } 

     public bool Equals(B other) 
     { 
      // this is the ??? comparison 
      return this.Id == other.Id; 
     } 

     public override bool Equals(object obj) 
     { 
      if (obj is B) 
       return this.Equals(obj as B); 
      else 
       return object.ReferenceEquals(this, obj); 
     } 

     public override int GetHashCode() 
     { 
      // this is the wanted comparison 
      return this.Code.GetHashCode(); 
     } 
    } 
} 

출력은 다음과 같습니다 경우

one A 
one B 

가 출력 I가 내가 그것을 경우 B 클래스의 Equals를 오버라이드 (override) 할 필요가 무엇인지 자신에게 물어 지금

one A 
one B 
one B+ 

입니다 Code = "one B+" 댓글을 달았습니다 이것이 비교에 아무런 영향을 미치지 않는 것 같습니다.

GetHasCode()은 그러한 종류의 비교에 충분합니까?

+0

가능한 복제본 [Equals()/GetHashCode()를 올바르게 구현 했습니까?] (http://stackoverflow.com/questions/5700099/have-i-implemented-equals-gethashcode-correctly) –

답변

12

EqualsGetHashCode 사이의 관계에 대해 알아야 할 사항은 다음과 같습니다.

해시 코드는 요소가 존재할 것으로 예상되는 "버킷"을 빠르게 찾기 위해 해시 테이블에서 사용됩니다. 요소가 서로 다른 두 개의 버킷에있는 경우 요소가 동일하지 않을 수 있습니다.

이것의 결과는 짧은 부정적인 검사로, 고유성을 결정하는 목적으로, 해시 코드를 볼해야한다는 것입니다 : 두 개체가 서로 다른 해시 코드가있는 경우, 즉, 그들이 있습니다 하지 동일 (그들의 Equals 메서드가 무엇을 반환하는지에 관계없이).

두 개의 객체가 동일한 해시 코드를 갖는 경우 해시 테이블의 동일한 버킷에 있습니다. 그런 다음Equals 메서드는 평등을 결정하기 위해 호출됩니다.

따라서 GetHashCode이 같아야한다고 생각하는 두 개의 객체에 대해 동일한 값을 반환해야합니다.

4

항상 과 호환되는 구현으로 덮어 써야합니다. 해시 코드 일치/불일치는 각각 " 평등"및 "비 동일성"을 의미합니다. 해시 코드 그 자체가 인 것은 동일하지 않음을 나타냅니다. 따라서 해시 코드 일치 항목을 찾거나 값 그룹을 만드는 데 사용하면 Equals이 계속 일치하는지 확인합니다.

두 가지가 일치하지 않으면 일치하는 항목을 찾을 수 없습니다.

3

메서드는 GetHashCode 메서드를 사용하여 항목 간의 불평등을 확인하고 Equals 메서드를 사용하여 같음을 확인합니다.

우선 해시 코드를 사용하여 어떤 항목이 동일하지 않은지 즉, 서로 다른 해시 코드를 갖는지를 빠르게 비교 한 다음 동일한 해시 코드를 가진 항목을 비교하여 실제로 어떤 항목이 동일한 지 비교합니다.

B 클래스를 구현할 때 GetHashCodeEquals 메서드를 일관되게 구현하지 않아 비교가 제대로 작동하지 않습니다. 두 개의 B 개체에는 서로 다른 해시 코드가 있으므로 서로 비교되지 않습니다. 동일한 것으로 간주되는 두 항목은 동일한 해시 코드를 반환해야합니다.

클래스가 IEquatable<T> 인터페이스를 구현하는 경우 Equals(T) 메서드가 사용되며, 그렇지 않은 경우 Equals(object) 메서드가 사용됩니다.