IComparable 과 IComparer 는 비슷한 일을 하지만 근본적인 차이가 있다.
이 게시글에서는 두 인터페이스의 용도와 차이에 대해 알아볼 것이다.
IComparable
C#의 커스텀 클래스는 기본적으로 "비교 불가능"이다.
객체의 수많은 정보들 중에서 무엇을 기준으로 해야 할지 모르기 때문이다.
public class Person
{
public string Name { get; }
public int Age { get; }
public Person(string name, int age)
{
Name = name;
Age = age;
}
}
class Program
{
static void Main()
{
Person jack = new Person("Jack", 20);
Person john = new Person("John", 24);
Person tom = new Person("Tom", 17);
Person[] people = { jack, john, tom };
Array.Sort(people);
foreach (Person p in people)
{
Console.WriteLine(p.Name);
}
}
}
객체를 "비교 가능"하게 만들기 위해서는 IComparable 인터페이스를 상속받아 그 클래스를 comparable, 즉 비교 가능한 클래스로 만들어야 한다.
또한 인터페이스에서 요구하는 메서드인 CompareTo 메서드를 구현하여 객체들 간의 선후 관계를 정의해야 한다.
public class Person : IComparable<Person>
{
public string Name { get; }
public int Age { get; }
public Person(string name, int age)
{
Name = name;
Age = age;
}
int IComparable<Person>.CompareTo(Person other)
{
return Age - other.Age;
}
}
CompareTo 의 규칙은 매우 간단하다.
음수를 반환한다면 other보다 순서가 빠른 것이고, 양수를 반환한다면 순서가 느린 것이다.
0은 순서가 같음을 의미한다. (다만 C#의 Sort는 unstable하므로 원래 순서가 유지된다는 보장은 없다)
구현이 귀찮다면 기본 자료형의 CompareTo 를 활용하는 방법도 있다.
int IComparable<Person>.CompareTo(Person other)
{
return other.Name.CompareTo(Name);
}
C#의 기본 자료형은 이미 자신만의 CompareTo 를 가지고 있다.
그렇기에 아무런 사전 작업 없이 Sort가 가능한 것이다.
string의 경우 비교가 조금 번거롭기 때문에 String.CompareTo 를 잘 이용하면 사전순과 그 역으로 쉽게 정렬할 수 있다.
IComparer
IComparable 이 1인칭이었다면 IComparer 는 3인칭이라고 할 수 있다.
제 3의 객체에게 비교를 위탁하는 것인데, IComparable 보다 번거로운 대신 활용 범위가 넓다.
class Program
{
static void Main()
{
int[] nums = { 3, 2, 7, 4, 6, 1, 8, 9, 5 };
Array.Sort(nums);
foreach (int num in nums)
{
Console.WriteLine(num);
}
}
}
수열을 내림차순으로 정렬하고 싶지만 정수형의 CompareTo 메서드를 수정할 방법이 없는 상황이다.
이럴 때는 IComparer 를 통해 새로운 선후 관계를 정의하면 된다.
IComparable 과 마찬가지로, IComparer 를 상속받았다면 반드시 Compare 메서드를 구현해야 한다.
Compare 메서드는 CompareTo 와 논리 구조가 동일한데, 둘 다 반환값의 부호를 통해 객체의 선후 관계를 결정한다.
그러나 Compare 메서드는 3인칭이고 CompareTo 는 1인칭이라는 차이가 있다.
public class IntComparer : IComparer<int>
{
int IComparer<int>.Compare(int x, int y)
{
return y - x;
}
}
class Program
{
static void Main()
{
int[] nums = { 3, 2, 7, 4, 6, 1, 8, 9, 5 };
Array.Sort(nums, new IntComparer());
foreach (int num in nums)
{
Console.WriteLine(num);
}
}
}
새로운 비교 메서드인 Compare 를 통해 정렬된 모습이다.
기존의 CompareTo 는 무시되기 때문에 CompareTo 를 수정할 권한이 없을 때는 물론이고 CompareTo 가 아예 존재하지 않을 때도 사용할 수 있다.
단, 객체를 정렬할 때 반드시 IComparer 를 상속받은 객체를 인자로 전달해주어야 한다.
그렇지 않으면 정렬 메서드는 Compare 의 존재를 알 수 없다.
'언어 > C#' 카테고리의 다른 글
Delegate와 Action, Func, Predicate (0) | 2023.07.20 |
---|---|
C#의 동작 원리 (0) | 2023.02.03 |
C#에서 배열을 부분 참조하는 방법 (0) | 2022.12.29 |
댓글