2010-04-29 2 views
114

Food 클래스가 Food의 다른 인스턴스와 같을 때마다 테스트 할 수 있기를 바랍니다. 나중에 List와 비교하여 사용할 것이고 그 방법은 List.Contains()입니다. IEquatable<Food>을 구현하거나 Object.Equals()을 재정의해야합니까? MSDN에서 :IEquatable와 Object.Equals()를 그냥 오버 라이딩하는 것의 차이점은 무엇입니까?

이 방법은 T (목록의 값 유형)에 IEquatable.Equals 방법 오브젝트의 구현에 의해 정의 된 기본 같음 비교, 를 사용 의해 어떤지를 판정한다.

그럼 내 다음 질문은 : .NET Framework의 어떤 기능/클래스가 Object.Equals()을 사용합니까? 내가 처음부터 그것을 사용해야합니까?

+2

매우 유용한 설명 http://blogs.msdn.com/b/jaredpar/archive/2009/01/15/if-you-implement-iequatable-t-you-still-must-override-object- s-equals-and-gethashcode.aspx – nawfal

+1

@nawfal : 이미 수용된 대답에서 언급되었습니다. –

+0

가능한 복제본 [이해 IEquatable] (http://stackoverflow.com/questions/411500/understanding-equatable) – nawfal

답변

140

주된 이유는 성능입니다. 제네릭이 .NET 2.0에 도입되었을 때 그들은 List<T>, Dictionary<K,V>, HashSet<T> 등과 같이 일련의 깔끔한 클래스를 추가 할 수있었습니다. 이러한 구조는 GetHashCodeEquals을 많이 사용합니다. 그러나 값 유형을 위해 이것은 권투를 요구했다. IEquatable<T>은 강력하게 입력 된 Equals 메서드를 구현하는 구조를 허용하므로 복싱이 필요하지 않습니다. 따라서 일반 컬렉션에서 값 유형을 사용할 때 훨씬 더 우수한 성능을 제공합니다.

참조 유형이 많은 이점은 없지만 IEquatable<T> 구현은 System.Object의 캐스트가 자주 호출되는 경우 차이를 만들 수 있습니다.

Jared Parson's blog에서 언급했듯이 여전히 개체 재정의를 구현해야합니다.

+0

참조 형식 사이에 캐스트가 있습니까? 저는 캐스트가 한 종류의 객체에서 다른 캐스트로 명확하지 않은 캐스트를 할당 할 때 컴파일러에서 "문"이라고 생각한 것입니다. 이것은 컴파일 한 후에 코드가 거기에 캐스트가 있는지조차 알지 못한다는 것입니다. –

+5

C++에서는 true이지만 형식 안전을 적용하는 .NET 언어에서는 그렇지 않습니다. 런타임 캐스트가 있고 캐스트가 성공하지 못하면 예외가 발생합니다. 따라서 캐스팅 비용을 지불 할 때 실행 시간상의 벌점이 적습니다. 컴파일러는 업 캐스트를 최적화 할 수 있습니다. 예를 들어 object o = (object) "string"; 그러나 다운 캐스팅 - 문자열 s = (문자열) o; - 런타임에 실행해야합니다. – Josh

+1

알겠습니다. 우연히 .NET에 관한 그런 "더 깊은"정보를 얻을 수있는 곳이 어디 있습니까? 감사! –

34

MSDN에 따르면 Object.Equals(Object) 그래서 그들의 행동은 IEquatable(T).Equals 방법의 그것과 일관성이 있음을 GetHashCode 의 당신이 IEquatable(T)을 구현하는 경우

, 당신은 또한 기본 클래스를 오버라이드 (override) 할 필요가 구현 . Object.Equals(Object)을 재정의하는 경우 오버라이드 된 구현은 에서 클래스의 정적 Equals(System.Object, System.Object) 메소드로 호출됩니다. 이렇게하면 Equals 메서드를 호출 할 때마다 결과가 일관되게 반환됩니다. 결과는 입니다.

그래서 클래스가 사용되는 방법에 따라 둘 중 하나를 호출 할 수 있다는 점을 제외하고 두 함수간에 실제 기능상의 차이점이없는 것으로 보입니다. 성능 관점에서 볼 때 일반 버전을 사용하는 것이 좋습니다. 복싱/언 박싱 패널티가 없기 때문입니다.

논리적 인 관점에서 인터페이스를 구현하는 것이 좋습니다. 객체를 재정의해도 실제로 클래스가 실제로 동등하다는 것을 다른 사람에게 알리지 않습니다. 오버라이드는 do nothing 클래스이거나 얕은 구현 일 수 있습니다. 인터페이스를 명시 적으로 사용하면 "이봐, 이건 평등 검사에 유효하다!" 그것은 단지 더 나은 디자인입니다.

+0

네, 둘 다 좋은 지적입니다. –

+4

구조체는 Dictionary 또는 유사한 컬렉션에서 키로 사용하려는 경우 구조체에서 반드시 iEquatable (theirOwnType)을 구현해야합니다. 그것은 큰 성능 향상을 제공 할 것입니다. 상속받지 않는 클래스는 theirOwnType의 IEquatable를 구현하여 약간의 성능 향상을 얻습니다. 상속 가능한 클래스는 // IEquatable을 구현하지 않아야합니다. – supercat

19

조쉬가 실제적인 예를 들어 말한 것을 확장하십시오.조쉬에게 +1 - 나는 내 대답에 똑같이 쓰려고했다.

public abstract class EntityBase : IEquatable<EntityBase> 
{ 
    public EntityBase() { } 

    #region IEquatable<EntityBase> Members 

    public bool Equals(EntityBase other) 
    { 
     //Generic implementation of equality using reflection on derived class instance. 
     return true; 
    } 

    public override bool Equals(object obj) 
    { 
     return this.Equals(obj as EntityBase); 
    } 

    #endregion 
} 

public class Author : EntityBase 
{ 
    public Author() { } 
} 

public class Book : EntityBase 
{ 
    public Book() { } 
} 

이 방법으로, 모든 파생 된 클래스에 대해 즉시 사용할 수있는 재사용 가능한 Equals() 메소드가 있습니다.

+0

질문이 하나 더 있습니다. (EntityBase) obj 대신 "obj as EntityBase"를 사용하면 어떤 이점이 있습니까? 작풍의 사정 또는 전혀 어떤 이점 있는가? "obj as EntityBase"의 경우 –

+15

- obj가 EntityBase 유형이 아닌 경우 "null"을 전달하고 오류 또는 예외없이 계속 진행하지만 "(EntityBase) obj"의 경우에는 강제로 obj가 EntityBase에, obj가 EntityBase 형이 아닌 경우는 InvalidCastException가 슬로우됩니다. 그리고 예, "as"는 참조 유형에만 적용 할 수 있습니다. –

+0

아, 알겠습니다. 큰. 감사! –