티스토리 뷰
[Effective C# Item 20] IComparable<T>와 IComparer<T>를 이용하여 객체의 선후 관계를 정의하라
weekyear 2020. 10. 18. 14:24[Effective C# Item 20]
IComparable<T>와 IComparer<T>를 이용하여 객체의 선후 관계를 정의하라
컬렉션을 정의하거나 검색하려면 타입 내에 선후 관계를 판단할 수 있는 기능을 정의해야 한다.
이를 위해서 .NET 프레임워크는 객체의 선후 관계를 정의하는 인터페이스인 IComparable<T>와 IComparer를 제공한다. IComparable<T>를 이용하여 타입의 기본적인 선후 관계를 정의하고 IComparer<T>를 이용하여 기본적인 선후 관계 이외에 추가적인 선후 관계를 정의할 수 있다.
이번 항목에서 우리가 배울 것!
1. 객체의 선후 관계를 구현하는 방법
2. 인터페이스를 이용하여 .NET 프레임워크가 객체의 순서를 정렬하는 원리
그래서 만약 어떤 알고리즘이 특정 타입에 대해 더 효율적으로 동작한다고 생각된다면 그냥 그 타입을 이용하도록 작성하는 것도 좋다. 직전 Item 때 처럼 제약 조건을 설정하는 방법도 있지만 제약 조건이 항상 능사는 아니다.
CompareTo()
IComparable 인터페이스에는 CompareTo()라는 하나의 메서드만 정의되어 있다. 이 메서드는 현재 객체가 대상 객체보다 작으면 0보다 작은 값을, 같으면 0을, 크면 0보다 큰 값을 반환해야 한다.
.NET 환경이 제공하는 최신 API는 IComparable<T>를 사용하지만 일부 오래된 API들은 여전히 IComparable를 구현하기 때문에 IComparable<T>를 구현할 때는 IComparable를 같이 구현해줘야 한다.
제네릭이 아닌 IComparable 인터페이스
IComparable로 구현된 CompareTo() 메서드는 앞에 IComparable을 붙여줘서 이전 인터페이스로 구현된 메서드임을 드러내는 것이 좋다. 그런데 타입 매개변수를 취하지 않고 object를 매개변수로 취하는 IComparable은 상당히 많은 단점이 있는데 이 인터페이스를 구현하려면 매개변수에 대한 타입을 런타임에 확인해야 한다.
즉, CompareTo()에 올바르지 않은 객체를 전달하는 경우에도 아무런 방비가 없다. 올바른 객체를 전달한다고 하더라도 실제 비교를 위해서 박싱/언박싱 작업이 필요하게 되고 이 작업은 앞선 항목에서도 말한바와 같이 성능에 상당히 많은 비용을 지불해야 한다.
그럼 제네릭 버전이 아닌 IComparable 인터페이스를 왜 구현해야 하는지 의문이 들지도 모르겠다. 앞서 잠깐 얘기했었는데 여전히 제네릭을 쓰지 않는 많은 API들을 위해서 즉, 하위 호환성을 위해서 구현해야 한다. 짧게 얘기하자면 .NET 프레임워크 2.0 이전에 개발된 코드에서 이 타입을 사용하려면 반드시 이 인터페이스를 구현해야 한다.
IComparable을 구현할 때는 반드시 명시적으로 인터페이스를 구현하고 추가적으로 강력한 타입(strongly typed)의 public 오버로드 메서드도 함께 구현해야 한다. 이 오버로드된 메서드를 사용하면 더 빠르게 비교 연산을 수행할 수 있고 CompareTo 메서드의 오용 가능성을 줄일 수 있다.
IComparer
이제 추가적으로 정렬 기준을 제시하는 IComparer를 구현하기 위해 Customer 구조체 내에 중첩 클래스를 만든 후 새로운 클래스 (RevenueComparer)를 생성하도록 코드를 수정하고 이를 정적 속성으로 노출하도록 코드를 작성해보자.
이제 Customer 객체를 이름 순뿐만이 아니라 매출 순으로도 정렬할 수 있게 되었다.
정리
IComparable과 IComparer는 타입에 선후 관계를 제공하기 위한 표준 메커니즘이다. 기본적인 선후 관계는 IComparable을 통해 구현해야 한다.
IComparable을 구현해야 할 때는 관계 연산자도 함께 오버로딩하여 일관된 결과를 제공해야 한다.
IComparable.CompareTo()는 System.Object 타입의 매개변수를 취하므로 별도로 오버로딩 된 메서드를 제공해야 한다.
별도로 IComparer를 이용하면 추가적인 선후 관계를 정의할 수 있을 뿐 아니라 우리가 직접 개발하지 않는 타입에 대해서도 임의의 선후 관계를 추가로 정의할 수 있다.
IComparable, IComparer이라는 인터페이스 자체를 처음 알게 되었는데 편리하다고 느꼈다.
지금까지 정렬을 할 때는 DateTime, string, int와 같이 이미 만들어진 정렬만 사용할 수 있게 되었는데
이제 새로운 정렬 방법을 만들 수 있는 신문물을 받아 들이게 되었다.
적극 이용해보자.
참조 - Effective C# <강력한 C# 코드를 구현하는 50가지 전략과 기법, 이펙티브>, 빌 와그너, 김명신, 한빛미디어
'Programming > Effective C#' 카테고리의 다른 글
[Effective C# Item 22] 공변성과 반공변성을 지원하라 (0) | 2020.10.18 |
---|---|
[Effective C# Item 21] 타입 매개변수가 IDisposable을 구현한 경우를 대비하여 제네릭 클래스를 작성하라 (0) | 2020.10.18 |
[Effective C# Item 19] 런타임에 타입을 확인하여 최적의 알고리즘을 사용하라 (0) | 2020.10.18 |
[Effective C# Item 18] 반드시 필요한 제약 조건만 설정하라 (0) | 2020.10.18 |
[Effective C# Item 17] 표준 Dispose 패턴을 구현하라 (0) | 2020.10.18 |