IEquatable과 Object.Equals ()를 재정의하는 것의 차이점은 무엇입니까?


185

내 원하는 Food것이 다른 인스턴스와 동일한 때마다 클래스를 테스트 할 수 있도록 Food. 나중에 List에 대해 사용하고 그 List.Contains()방법 을 사용하고 싶습니다 . 구현 IEquatable<Food>또는 재정의 해야합니까 Object.Equals()? MSDN에서 :

이 메소드는 오브젝트의 IEquatable.Equals 메소드 (목록의 값 유형)에 대한 정의에 정의 된대로 기본 동등 비교기를 사용하여 동등성을 판별합니다.

그래서 다음 질문은 .NET 프레임 워크의 어떤 함수 / 클래스를 사용 Object.Equals()합니까? 처음에 사용해야합니까?


3
아주 좋은 설명이 여기 blogs.msdn.com/b/jaredpar/archive/2009/01/15/…
nawfal

답변:


214

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

참조 유형은 그다지 도움이되지 않지만 IEquatable<T>구현을 통해 System.Object자주 호출되는 경우 차이를 만들 수 있는 캐스트를 피할 수 있습니다.

Jared Parson의 블로그 에서 언급했듯이 여전히 Object 재정의를 구현해야합니다.


참조 유형간에 캐스트가 있습니까? 나는 캐스트가 한 종류의 객체에서 다른 객체로 명백한 캐스트를 할당 할 때 컴파일러에 "문장"이라고 생각했습니다. 이것은 컴파일 후에 코드에 캐스트가 있다는 것을 알지 못할 것입니다.
삼키는 elysium

7
C ++에서는 그렇지만 유형 안전을 시행하는 .NET 언어는 그렇지 않습니다. 런타임 캐스트가 있으며 캐스트에 실패하면 예외가 발생합니다. 따라서 캐스팅 비용을 지불하는 데 약간의 런타임 페널티가 있습니다. 컴파일러는 업 캐스트를 최적화 할 수 있습니다. 예를 들어 object o = (object) "string"; 그러나 다운 캐스팅-문자열 s = (문자열) o; -런타임시 발생해야합니다.
Josh

1
내가 참조. 우연히 .NET에 대한 "더 깊은"정보를 얻을 수있는 곳이 있습니까? 감사!
삼켜 elysium

7
Jeff Richter의 C #과 Jon Skeet의 Depth의 C #을 통한 CLR을 권장합니다. 블로그에 관해서는, Wintellect 블로그, msdn 블로그 등이 좋습니다.
Josh

IEquatable<T>인터페이스는 개발자에게 public bool Equals(T other) 클래스 나 구조체에 멤버 를 포함 시키도록 상기시키는 것 이상을 수행 합니까 ? 인터페이스의 유무는 런타임시 차이가 없습니다. 과부하 Equals가 필요한 모든 것 같습니다.
mikemay

48

MSDN 에 따르면 :

당신이 구현하는 경우 IEquatable<T>, 당신은 또한의 기본 클래스 구현을 오버라이드 (override) Object.Equals(Object)하고 GetHashCode 그래서 그들의 행동은 그와 일치하는지 IEquatable<T>.Equals 방법. 당신은 대체를 할 경우 Object.Equals(Object), 재정의 된 구현은 정적에 대한 호출에서 호출되는 Equals(System.Object, System.Object)클래스에 방법. 이렇게하면 Equals메소드 의 모든 호출이 일관된 결과를 리턴합니다.

따라서 클래스가 어떻게 사용되는지에 따라 호출 될 수 있다는 점을 제외하고는 둘 사이에 실질적인 기능적 차이가없는 것 같습니다. 성능 관점에서 볼 때 권투 / 언 박싱 페널티가 없기 때문에 일반 버전을 사용하는 것이 좋습니다.

논리적 관점에서 인터페이스를 구현하는 것이 좋습니다. 객체를 재정의한다고해서 클래스가 실제로 동일하다는 사실을 다른 사람에게 알리지는 않습니다. 재정의는 클래스를 수행하지 않거나 얕은 구현 일 수 있습니다. "이것은 평등 검사에 유효합니다!" 더 나은 디자인입니다.


9
Structs는 Dictionary 또는 이와 유사한 컬렉션에서 키로 사용하려는 경우 반드시 iEquatable (of theirOwnType)을 구현해야합니다. 성능이 크게 향상됩니다. 상속 불가능한 클래스는 IEquatable (of theirOwnType)을 구현하여 약간의 성능 향상을받습니다. 상속 가능한 클래스는 IEquatable을 // not // 구현하지 않아야합니다.
supercat

30

Josh가 말한 내용을 실제 사례로 확장합니다. 조쉬에게 +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 () 메서드가 있습니다.


하나만 더 질문 해 (EntityBase) obj 대신 "obj를 EntityBase"로 사용하면 어떤 이점이 있습니까? 스타일의 문제입니까 아니면 전혀 이점이 있습니까?
삼키는 elysium

22
"obj를 EntityBase로"인 경우-obj가 EntityBase 유형이 아닌 경우 "null"을 전달하고 오류나 예외없이 계속 진행하지만 "(EntityBase) obj"의 경우 obj를 강제로 캐스팅하려고합니다. EntityBase에 obj가 EntityBase 유형이 아닌 경우 InvalidCastException이 발생합니다. 그리고 "as"는 참조 유형에만 적용 할 수 있습니다.
이것. __curious_geek

1
Jared Par의 블로그에 대한 Josh의 링크는 GetHashCode를 재정의해야한다고 제안합니다. 그렇지 않습니까?
Amicable

3
실제로 구현에서 제공하는 추가 가치를 얻지 못합니다. 추상 기본 클래스가 해결하는 문제를 명확히 할 수 있습니까?
Mert Akcakaya

1
@Amicable-예. Object.Equals (Object)를 재정의 할 때마다 컨테이너가 작동하도록 GetHashCode도 재정의해야합니다.
namford

0

를 호출하면 object.Equals값 유형에 대한 비싼 권투가 발생합니다. 성능에 민감한 시나리오에서는 바람직하지 않습니다. 해결책은 IEquatable<T>입니다.

public interface IEquatable<T>
{
  bool Equals (T other);
}

배후의 아이디어 IEquatable<T>는 결과는 object.Equals같지만 더 빠르다는 것입니다. 구속 조건 where T : IEquatable<T>은 다음과 같은 일반 유형과 함께 사용해야합니다.

public class Test<T> where T : IEquatable<T>
{
  public bool IsEqual (T a, T b)
  {
    return a.Equals (b); // No boxing with generic T
  }
}

그렇지 않으면에 바인딩됩니다 slower object.Equals().

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.