2011-09-04 4 views
29

IComparable과 일반 IComparable<T>을 모두 구현해야합니까? 그 중 하나만 구현하면 제한이 있습니까?IComparable 및 IComparable <T>

+0

을 'IComparable '에 대한 코드를 작성해야합니다. 실제 비교를 일반적인 구현에 위임하여 'IComparable'을 무료로 얻을 수 있습니다. –

답변

18

예, 모두 구현해야합니다.

하나를 구현하면 다른 코드에 의존하는 코드는 실패합니다.

IComparable 또는 IComparable<T> 중 하나만 사용하는 코드가 있지만 둘 다 사용하지는 않으므로 코드를 모두 구현하면 코드가 이러한 코드와 작동합니다.

+0

모든 코드를 제어하는 ​​경우 일반 버전 만 구현해야한다고 결정할 수 있습니까? 아니면 프레임 워크 코드 중 일부가 비 제네릭 버전을 필요로합니까? –

+0

@David, 일부 프레임 워크 클래스 (예 : 컬렉션)는 둘 중 하나에 의존 할 수 있습니다. –

+5

@David - 'IComparable'은 일부 프레임 워크 코드에서 확실히 사용됩니다. 나는'Array.Sort'와'ArrayList.Sort'가 그것을 사용한다고 생각한다. – Oded

4

IEquatable <T>은 봉인되지 않은 클래스로 일반적으로 구현되어서는 안되지만 구현이 단순히 Object.Equals를 호출하지 않는 한 상속과 함께 이상하게 재생 될 것이므로 (그럴 경우 무의미 함) 반대 상황이 발생합니다. 일반 IComparable <T>. Object.Equals 및 IEquatable에 대한 의미는 <T>으로, IEquatable <T>이 정의 될 때마다 해당 동작은 Object.Equals의 동작을 미러링해야합니다 (더 빠르며 복싱을 피하려면 제외). DerivedFoo 유형으로 간주 될 때 equal로 비교되는 DerivedFoo 유형의 두 객체는 ​​Foo 유형의 객체로 간주 될 때 equal을 비교해야하며 그 반대의 경우도 마찬가지입니다. 반면 DerivedFoo 유형의 두 객체는 ​​유형 Foo로 간주 될 때 동등하게 순위 지정되어야합니다. 이를 보장하는 유일한 방법은 IComparable <T>을 사용하는 것입니다.

예를 들어 ScheduledEvent 클래스에 ScheduledTime (DateTime 유형) 및 ScheduledAction (MethodInvoker 유형) 필드가 있다고 가정합니다. 이 클래스에는 하위 유형 SchedulerEventWithMessage (string 유형의 Message 필드 추가) 및 SchedulerEventWithGong (Double 유형의 GongVolume 필드 추가)이 포함됩니다. SchedulerEvent 클래스는 ScheduledTime에 의해 자연 순서가 있지만, 서로 비 순차적 인 이벤트는 서로 다름을 전제로 가능합니다. SchedulerEventWithMessage 및 SchedulerEventWithGong 클래스도 자연스러운 순서를 가지지 만 SchedulerEvent 클래스의 항목과 비교할 때는 그렇지 않습니다.

두 개의 SchedulerEventWithMessage 이벤트 X와 Y가 동시에 스케줄되지만 X.Message가 "aardvark"이고 Y.Message가 "zymurgy"라고 가정합니다. (IComparable <SchedulerEvent>) X.CompareTo (Y)는 이벤트가 동등한 시간이기 때문에 0을보고하지만 (IComparable <SchedulerEventWithMessage>) X) .CompareTo (Y)는 음수를 반환해야합니다 ("aardvark" "zymurgy"이전에 정렬). 클래스가 그런 식으로 행동하지 않으면 SchedulerEventWithMessage 및 SchedulerEventWithGong 개체가 혼합 된 목록을 일관되게 정렬하는 것이 어렵거나 불가능합니다.

덧붙여 말하자면, IEquatable의 의미론을 갖는 것이 유용 할 것이라고 주장 할 수 있습니다. <T>은 유형 T의 멤버의 기초 만 개체를 ​​비교합니다. IEquatable <SchedulerEvent>은 ScheduledTime 및 ScheduledAction이 같은지 확인하지만 SchedulerEventWithMessage 또는 SchedulerEventWithGong에 적용해도 Message 또는 GongVolume 속성을 확인하지 않습니다. 사실, 그 유용한 의미를 IEquatable <T> 메서드에 대한 유용한 의미가 될 것입니다 및 그 같은 의미를 선호하는 있지만 하나의 문제 : Compareer <T>.Default.GetHashCode (T) 항상 같은 함수 Object.GetHashCode() 관계없이 호출합니다. 이것은 IEquatable <T>의 기능을 다른 유형 T로 변경하는 기능을 크게 제한합니다.

+0

매우 흥미로운 대답입니다. –

19

Oded는 구현 중 하나에 만 의존하는 컬렉션과 다른 클래스가 있기 때문에 둘 다 구현해야합니다.

그러나 트릭이 있습니다. IComparable <T>은 예외를 발생시키지 않아야하며 IComparable은 있어야합니다. IComparable <T>을 구현할 때 T의 모든 인스턴스를 서로 비교할 수 있도록해야합니다. 여기에는 null도 포함됩니다 (null을 T의 모든 null이 아닌 인스턴스보다 작게 처리하면 괜찮을 것입니다).

그러나 일반적으로 IComparable은 System.Object를 허용하므로 생각할 수있는 모든 개체가 T의 인스턴스와 비교 될 수 있다고 보장 할 수 없습니다. 따라서 T가 아닌 인스턴스가 IComparable에 전달되면 System.ArgumentException . 그렇지 않은 경우 IComparable <T> 구현에 대한 호출을 라우팅합니다. 여기

은 예입니다

public class Piano : IComparable<Piano>, IComparable 
{ 
    public int CompareTo(Piano other) { ... } 
    ... 
    public int CompareTo(object obj) 
    { 

     if (obj != null && !(obj is Piano)) 
      throw new ArgumentException("Object must be of type Piano."); 

     return CompareTo(obj as Piano); 

    } 
} 

이 예제는 T >에서 IComparable <을 구현할 때 처리해야한다는 부작용의 광범위한 분석이 포함 된 더 이상 기사의 일부입니다 How to Implement IComparable<T> Interface in Base and Derived Classes

관련 문제