Creative Commons License

Microsoft .NET

닷넷!시작하기
닷넷! Ver 2.0~
닷넷!스킬업
웹개발
윈폼개발
실용모듈개발
Tip & Tech
하루 한 문법

Microsoft .NET 개발자들을 위한 공간입니다. 기초강의에서 부터 고급 기술 정보 및 팁등을 다루도록 하겠습니다.

.

닷넷!스킬업

닷넷 기술을 조금 더 깊이 다루고자 합니다. 특정 주제를 정하지 않고 이슈 발생 시 마다 체계적으로 정리하여 공유하겠습니다. 이전 자료를 옮겨온 곳이기도 합니다.

IComparable 인터페이스

작성자 : 박종명
최초 작성일 : 2008-06-30 (월요일)
최종 수정일 : 2008-06-30 (월요일)
조회 수 : 2865

IComparable 인터페이스 』

 

1. IComparable 개요

 

이번 글에서는 Microsoft .NET 의 많은 Interface 중 비교와 관련된 표준 규약인 IComparable 에 대해 알아보도록 하자. 우선 IComparable MSDN 정의를 살펴보자.

 

 

 

설명에서 알 수 있듯이 IComparable 인터페이스는 두 자료구조에 대한 비교를 처리하기 위한 규약인 것을 알 수 있다. 이러한 비교 처리는 자료에 대한 비교뿐만 아니라 비교에 의한 정렬 등의 용도로도 사용된다고 한다.

Array 클래스의 Sort 메서드는 배열의 요소들을 정렬하는 메서드인데 내부적으로 각 요소들의 비교를 통해 이루어진다. 배열의 각 요소들은 IComparable 를 구현하고 있어야만 Array.Sort 로 정렬이 가능한 것이다.

 

IComparable 는 단 하나의 멤버를 가지고 있다.

 

 

CompareTo 메서드는 현재 객체와 동일한 형식의 다른 객체와의 (비즈니스 요건에 맞는 고유한) 비교를 수행하도록 구현해야 한다.

 

 

 

비교대상인 객체를 인자로 전달 받아서 현재 객체와의 비교를 수행한 뒤 수형으로 비교 결과 값을 반환하도록 구현해야 한다. 위의 표대로 결과 값은 비교를 통하여 0 또는 0보다 작거나 큰 값을 반환하도록 한다.

 

 

2. IComparable 구현한 자료구조

 

.NET Framework 의 많은 자료구조들이 IComparable 을 구현하고 있다.

우선 값 형식인 정수형 데이터의 정의를 보자

 

Int32 구조체의 정의를 보면 IComparable 를 구현하고 있다.

따라서 int 두 값을 비교하기 위한 다음의 코드가 가능하다.

int i = 1;

int j = 2;

Console.WriteLine(i.CompareTo(j));

 

INT 이외에도 많은 자료구조가 이 인터페이스를 구현하고 있는데 다음 그림은 MSDN 에서 검색한 결과이다.

 

많은 값 형식 또는 참조형식 자료구조들이 IComparable 을 구현하고 있음을 알 수 있다.

 

3. 사용자 정의 클래스 만들기 (IComparable 구현)

 

그럼, 이제 IComparable 을 구현하는 클래스를 직접 만들어 보도록 하자.

다음과 같은 비즈니스 요건이 있다고 가정한다

 

사람이라는 객체가 있다.

모든 사람은 키(신장)라는 속성을 가지는데 이 () 속성을 기반으로 사람과 사람을 비교할 수

있도록 만들어야 한다.

또한 사람들을 모은 (사람)배열은 키로 정렬되어야 한다

 

 

우선 사람을 표현하기 위한 Person 이라는 클래스를 만들고 키(신장) 속성을 부여한 뒤 IComparable 인터페이스를 구현하도록 하여 키(신장)으로 비교 가능토록 구현하도록 한다

 

public class Person : System.IComparable

{

    //(신장)

    private int stature;

    public int Stature

    {

        get { return stature; }

        set { stature = value; }

    }

 

    //생성자

    public Person(int stature)

    {

        this.stature = stature;

    }

 

    #region IComparable 멤버

    public int CompareTo(object obj)

    {

        if (obj is Person)

      {

            Person person = (Person)obj;

            return this.stature.CompareTo(person.Stature);

        }

      //전달받은 비교대상 객체가 Person 타입이 아니면 Exception 을 일으키도록 한다

       throw new ArgumentException("object is not a Person");

    }

    #endregion

}

 

Person 클래스의 CompareTo 메서드는 Object 타입의 객체를 매개변수로 전달받아서 Person 객체로 형 변환 한 뒤 (신장) 속성을 서로 비교하여 그 결과를 반환하도록 한다.

 

아래의 코드가 이 설명에 해당하는 코드이다

Person person = (Person)obj;

return this.stature.CompareTo(person.Stature);

 

현재 자신의 객체의 키 속성(stature) 과 전달받은 객체의 키 속성(person.Stature) 를 역시 CompareTo 로 비교하고 있다. 앞서 말했듯이 정수형 IComparable 를 구현하고 있기 때문에 가능한 것이다.

 

이제 두 사람 객체를 만들어 실제 비교를 해 보도록 하자.

 

Person person1 = new Person(175);

Person person2 = new Person(180);

 

int result = person1.CompareTo(person2);

 

if (result < 0)

{

      Console.WriteLine("person1 이 작습니다");

}

else if (result > 0)

{

       Console.WriteLine("person1이 더 큽니다");

}

else

{

       Console.WriteLine("두 사람의 키가 같습니다");

}

 

결과를 확인 해 보면 키(신장) 의 값에 따라 비교되는 것을 확인 할 수 있을 것이다.

 

또한 Person 클래스가 IComparable 를 구현하였기 때문에,

Person 객체가 아닌 .NET Framework System.Collections.Comparer 의해서도 두 객체를 다음과 같이 비교할 수 있게 된다.

System.Collections.Comparer c = new System.Collections.Comparer(new System.Globalization.CultureInfo("ko", false));

Console.WriteLine(c.Compare(person1, person2));

 

그리고 두 번째 요구사항인 사람 배열의 정렬을 보자.

이미 CompareTo를 구현하고 있기 때문에 Array 클래스의 Sort 를 통해 키(신장)으로 정렬이 가능하다.
아래 코드를 보자.

 

//사람들 배열 생성

Person[] persons = new Person[] {

               new Person(180),

                new Person(175),

                new Person(170),

                new Person(165),

                new Person(160),

};

 

//정렬하지 않은 상태

Console.WriteLine("정렬하지 않은 상태");

foreach (Person p in persons)

{

      Console.WriteLine(p.Stature);

}

 

//정렬하기

Array.Sort(persons);

 

//(신장)로 정렬한 상태

Console.WriteLine("(신장)로 정렬한 상태");

foreach (Person p in persons)

{

      Console.WriteLine(p.Stature);

}

 

위 코드에 대한 결과 화면은 다음과 같다

 

키로 정렬 되었음을 알 수 있다.

 

 

4. IComparable를 구현함으로써 얻는 이점

 

언뜻 생각해 보면 Person 객체들의 키 비교를 위해서 IComparable 를 구현하지 않고 직접 메서드를 정의해서
사용해도 된다.
그러나 인터페이스는 일종의 규약이다.

IComparable 를 구현함으로 써 얻는 이점은 다음과 같다.

-         언어의 표준 규약이므로 코드의 일관된 프로그래밍 모델을 지원하게 된다

-         .NET System.Collections.Comparer 클래스에 의해 비교할 수 있게 된다

-         Array 클래스를 통해 해당 타입의 배열을 정렬할 수 있게 된다

-         기타 등등……

이와 같이 미리 규약 된 인터페이스를 준수하는 프로그래밍은 많은 이점을 가져다 준다.

 

 

 

5. 배열의 역순 정렬

 

이로써 IComparable 인터페이스에 대한 설명을 마치고 앞서 살펴본 배열의 정렬을 역순으로 하는 방법에 대해 알아 보자. 배열의 역순 정렬은 MSDN 에 아주 심플하고 구체적인 샘플도 나와있다.

 

앞서 Person 을 정렬한 코드에 다음과 같이 다시 역순으로 정렬하여 원상복귀 시켜보자

 

public class myReverserClass : System.Collections.IComparer

{

      // Calls CaseInsensitiveComparer.Compare with the parameters reversed.

    int System.Collections.IComparer.Compare(Object x, Object y)

    {

        return ((new System.Collections.CaseInsensitiveComparer()).Compare(y, x));

      }

}

 

System.Collections.IComparer myComparer = new myReverserClass();

 

//역순 정렬

Array.Sort(persons, myComparer);

 

//다시 키(신장)을 역순으로 정렬한 상태

Console.WriteLine("(신장)로 정렬한 상태");

foreach (Person p in persons)

{

          Console.WriteLine(p.Stature);

}

 

결과를 확인해 보면 역순 정렬을 통해 다시 배열의 정렬순서가 원상태로 되었다. 자세한 설명은 다음 MSDN 을 참고하도록 한다.

ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.NETDEVFX.v20.ko/cpref2/html/

M_System_Array_Sort_1_eac9ec86.htm

 

 

 

 

6. .NET 2.0 System.IComparable<T> 인터페이스

 

지금까지 알아본 IComparable 은 은 닷넷 1.x 부터 존재하던 인터페이스 이지만 System.IComparable<T>
.NET 2.0
에 새롭게 추가된 인터페이스이다.

 

.NET 2.0 의 새로운 개념인 Generic 이 적용된 IComparable 라 보면 되겠다.

 

Generic 의 장점을 그대로 계승할 수 가 있는데, 우선 다음의 코드를 보자.

public int CompareTo(object obj)

{

     if (obj is Person)

     {

         Person person = (Person)obj;

          return this.stature.CompareTo(person.Stature);

     }

 

     //전달받은 비교대상 객체가 Person 타입이 아니면 Exception 을 일으키도록 한다

     throw new ArgumentException("object is not a Person");

}

 

위 코드는 앞서 작성한 Person CompareTo 메서드 이다.

Generic 을 사용하지 않을 경우에는 object 타입을 매개변수로 전달받기 때문에 타입 체크는 물론 형 변환(Down Casting) 이 일어나야 한다. 그리고 형식이 불일치 할 경우 적절한 오류 처리도 포함되어야 한다.

 

그러나 Generic 을사용함으로 타입 안정성이 확보되고 불필요한 형변환 작업이 없어 지므로

약간이나마 성능을 향상 시킬 수 있고 프로그램 안정성이 보장된다고 볼 수 있다.

 

즉 위의 코드는 다음과 같이 간단히 처리할 수 있을 것이다

 

public int CompareTo(Person obj)

{    

  return this.stature.CompareTo(obj.Stature);

}

 

이름
비밀번호
홈페이지
ME <- 왼쪽의 문자를 오른쪽 박스에 똑같이 입력해 주세요