2009-02-19 5 views
25

POINT2 클래스 말할 및 이하 같음은 다음 경우, OBJ 걸리는 하나사용자 정의 유형에 대해 Equals를 가장 잘 구현하는 방법은 무엇입니까?

public override bool Equals (object obj) 
{ 
    // STEP 1: Check for null 
    if (obj == null) 
    { 
     return false; 
    } 

    // STEP 3: equivalent data types 
    if (this.GetType () != obj.GetType ()) 
    { 
     return false; 
    } 
    return Equals ((Point2) obj); 
} 

public bool Equals (Point2 obj) 
{ 
    // STEP 1: Check for null if nullable (e.g., a reference type) 
    if (obj == null) 
    { 
     return false; 
    } 
    // STEP 2: Check for ReferenceEquals if this is a reference type 
    if (ReferenceEquals (this, obj)) 
    { 
     return true; 
    } 
    // STEP 4: Possibly check for equivalent hash codes 
    if (this.GetHashCode () != obj.GetHashCode ()) 
    { 
     return false; 
    } 
    // STEP 5: Check base.Equals if base overrides Equals() 
    System.Diagnostics.Debug.Assert (
     base.GetType () != typeof (object)); 

    if (!base.Equals (obj)) 
    { 
     return false; 
    } 

    // STEP 6: Compare identifying fields for equality. 
    return ((this.X.Equals (obj.X)) && (this.Y.Equals (obj.Y))); 
} 

답변

18

뿐만 아니라 guidelines on MSDN의 전체 세트가있다. 당신은 그것들을 잘 읽어야합니다, 그것은 까다 롭고 중요합니다. 내가 가장 도움이 발견

몇 점 : 당신은 일반적으로 회원에 의한 회원 비교 할 것 struct Point에 있도록

  • 값 유형, 신원이 없습니다.

  • 참조 유형에는 일반적으로 ID가 있으므로 Equals 테스트는 일반적으로 ReferenceEquals에서 중단됩니다 (기본값, 재정의 할 필요 없음). 그러나 문자열과 class Point2과 같은 예외가 있습니다. 객체에는 유용한 ID가 없으며 등호 멤버를 재정 의하여 고유 한 의미를 제공합니다. 그 상황에서 가이드 라인을 따라 null 및 기타 유형의 사례를 먼저 파악하십시오.

  • 그리고 GethashCode()operator==도 동기화해야하는 충분한 이유가 있습니다.

28

:

public override bool Equals (object obj) 

public bool Equals (Point2 obj) 

이것은 유효 C# 3에 도시 된 하나 obj의 타입이 Point2라면, 타입 특정 Equals를 호출하십시오. Equals 유형 특정 내부에서 모든 멤버가 동일한 값을 갖는지 확인하십시오.

public override bool Equals (object obj) 
{ 
    return Equals(obj as Point2); 
} 

public bool Equals (Point2 obj) 
{ 
    return obj != null && obj.X == this.X && obj.Y == this.Y ... 
    // Or whatever you think qualifies as the objects being equal. 
} 

"같음"개체가 동일한 해시 코드를 가지도록 GetHashCode를 재정의해야합니다.

+0

못해이 객체 obj'는 구조체 인'경우에 날려가있다? – row1

+0

@ row1 아니요. 구조체가 박스 처리되며 상자형 구조체는 as 연산자가 평가 될 때 'null'이됩니다. 정의 된 타입이 구조체라면 'as'를 사용하는 대신 명시 적 캐스트를해야합니다 (또는 nullable 구조체를 사용하십시오). nullable 구조체가 아닌 경우 null 검사도 제거합니다. – Servy

+0

매우 간단하고 합리적인 구현, 나는 그것을 좋아한다, 고맙습니다. –

2
  • 신원이 의미하는 바를 정의하십시오. 참조 신원이 다음 기본 상속 된 동등 함이 작동하면 정의하십시오.
  • 값 유형 (따라서 값 ID)을 정의해야하는 경우.
  • 클래스 유형이지만 값 의미가있는 경우 다음을 정의하십시오. 가능성이

당신은 에 모두 재정의 같음 (객체)와 후자는 권투를 피할 수 있기 때문에 (합니다 MyType)를 같음을 정의합니다. 그리고 평등 연산자를 재정의하십시오.

.NET Framework 지침서 (2 차 에디션)에는 더 많은 적용 범위가 있습니다. 다니엘 L 말했다

0

거짓말은

public override bool Equals(object obj) { 
    Point2 point = obj as Point2; // Point2? if Point2 is a struct 
    return point != null && this.Equals(point); 
} 

public bool Equals(Point2 point) { 
    ... 
} 
-1
public override bool Equals (object obj) 
{ 
    // struct 
    return obj is Point2 && Equals ( (Point2) value); 
    // class 
    //return Equals (obj as Point2); 
} 

public bool Equals (Point2 obj) 
7

나를 위해 일한 기술은 다음과 같습니다. 참고, 나는 단지 하나의 속성 (Id)을 기준으로 두 값을 비교하는 것입니다. 필요에 따라 조정하십시오

using System; 
namespace MyNameSpace 
{ 
    public class DomainEntity 
    { 
     public virtual int Id { get; set; } 

     public override bool Equals(object other) 
     { 
      return Equals(other as DomainEntity); 
     } 

     public virtual bool Equals(DomainEntity other) 
     { 
      if (other == null) { return false; } 
      if (object.ReferenceEquals(this, other)) { return true; } 
      return this.Id == other.Id; 
     } 

     public override int GetHashCode() 
     { 
      return this.Id; 
     } 

     public static bool operator ==(DomainEntity item1, DomainEntity item2) 
     { 
      if (object.ReferenceEquals(item1, item2)) { return true; } 
      if ((object)item1 == null || (object)item2 == null) { return false; } 
      return item1.Id == item2.Id; 
     } 

     public static bool operator !=(DomainEntity item1, DomainEntity item2) 
     { 
      return !(item1 == item2); 
     } 
    } 
} 
0

약간 다른 사람들이 이미 게시 한 양식의 약간의 변형 ...

using System; 
... 
public override bool Equals (object obj) { 
    return Equals(obj as SomeClass); 
} 

public bool Equals (SomeClass someInstance) { 
    return Object.ReferenceEquals(this, someInstance) 
     || (!Object.ReferenceEquals(someInstance, null) 
      && this.Value == someInstance.Value); 
} 

public static bool operator ==(SomeClass lhs, SomeClass rhs) { 
    if(Object.ReferenceEquals(lhs, null)) { 
     return Object.ReferenceEquals(rhs, null); 
    } 
    return lhs.Equals(rhs); 
    //OR 
    return Object.ReferenceEquals(lhs, rhs) 
      || (!Object.ReferenceEquals(lhs, null) 
       && !Object.ReferenceEquals(rhs, null) 
       && lhs.Value == rhs.Value); 
} 

public static bool operator !=(SomeClass lhs, SomeClass rhs) { 
    return !(lhs == rhs); 
    // OR 
    return (Object.ReferenceEquals(lhs, null) || !lhs.Equals(rhs)) 
      && !Object.ReferenceEquals(lhs, rhs); 
} 

이 불가능 A (ReferenceEquals이 동일한 파라미터 승/호출) 상관 중복 검사없이 값 비교 논리 ... 복제 방지 같음을 이용 == 연산자를 구현하는 방법 또는 불필요한 검사 (찾으려고 instance.Equals 메소드에서는 null), 명시 적 조건 ("ifs")이없는 경우. 유용한 무엇보다 마음을 티저로합니다.

I는이 생각할 수있는 가장 가까운, 그러나 추가 방법 :

public bool Equals (SomeClass someInstance) { 
    return Object.ReferenceEquals(this, someInstance) 
     || (!Object.ReferenceEquals(someInstance, null) && EqualsNonNullInstance(someInstance); 
} 

public static bool operator ==(SomeClass lhs, SomeClass rhs) { 
    return Object.ReferenceEquals(lhs, rhs) 
    || (!Object.ReferenceEquals(lhs, null) && !Object.ReferenceEquals(rhs, null) && lhs.EqualsNonNullInstance(rhs)); 
} 

//super fragile method which returns logical non-sense 
protected virtual bool EqualsNonNullInstance (SomeClass someInstance) { 
    //In practice this would be a more complex method... 
    return this.Value == someInstance.Value; 
} 

이 모두가 얼마나 지루하고 오류가 발생하기 쉬운 기억없이 가능해야한다처럼 을 느낀다 (I 거의 확신 위의 코드에 오류가 있습니다 ... 어떤 사람이 타입 을 단지 서브 클래스로 만들려고했기 때문에, 그냥 평범한 체크를 좀 더 간단하게하기 위해을 만들었습니다.) 앞으로 계속 모든 null 체크를 처리하는 정적 메서드를 만들 것입니다. 대리자를 수락하거나 값 비교 (유형을 유형으로 변경하는 유일한 부분)를 수행하기 위해 인터페이스와 요구 사항 및 인터페이스를 허용합니다.

비교할 필드/속성/메서드에 특성을 추가하고 컴파일러/런타임에서 모든 지루함을 처리 할 수 ​​있다면 좋을 것입니다.

또한 .Equals (object)가 true를 반환하거나 미친 똥이 발생할 수있는 모든 인스턴스에 대해 GetHashCode() 값이 동일해야합니다.

관련 문제