아티클 제목이 다소 아리송할지 모르겠다. ( 제목 붙이는 것이 쉽지가 않다 ㅡ.ㅡ )
이번 글은 2가지 예를 들면서 시작해보도록 하겠다.
먼저, 랜덤하게 Color를 추출하는 것에 대해 생각해보자.
쉽게, R,G,B값을 각각 난수를 발생해서 그 RGB의 조합으로 색상을 만들어내면 될것이다.
하지만, RGB값이 아닌 Black, Gray, Red, Violet, SteelBlue와 같은 이름을 가진 Color들을 알아내고 싶다면 어떻게 해야할까?
또한, 윈도우의 그림판과 같은 프로그램을 만들어본다고 생각해보자.
C#이 기본적으로 제공하는 ColorDialog를 사용하지 않는다면,(다이얼로그는 어차피 그림판 같은데는 어울리지 않는다)
색상을 선택할 수 있는 컨트롤을 직접 만들어서 사용해야 할것이다.
그럼, 일단 가장 먼저 Color의 리스트를 구성해야 할것인데, 이 역시 RGB를 사용하지 않는다면, 다음과 같이 정말 무식한(?) 코딩이 필요할 것이다.
ArrayList colors = new ArrayList(); colors.Add(Color.AliceBlue); colors.Add(Color.AntiqueWhite); colors.Add(Color.Aqua); colors.Add(Color.Aquamarine); colors.Add(Color.Azure); colors.Add(Color.Beige); colors.Add(Color.Bisque); colors.Add(Color.Black); colors.Add(Color.BlanchedAlmond); colors.Add(Color.Blue); colors.Add(Color.BlueViolet); colors.Add(Color.Brown); colors.Add(Color.BurlyWood); colors.Add(Color.CadetBlue); colors.Add(Color.Chartreuse); colors.Add(Color.Chocolate); colors.Add(Color.Coral); colors.Add(Color.CornflowerBlue); colors.Add(Color.Cornsilk); colors.Add(Color.Crimson); colors.Add(Color.Cyan); colors.Add(Color.DarkBlue); colors.Add(Color.DarkCyan); colors.Add(Color.DarkGoldenrod); colors.Add(Color.DarkGray); colors.Add(Color.DarkGreen); colors.Add(Color.DarkKhaki); colors.Add(Color.DarkMagenta); colors.Add(Color.DarkOliveGreen); .... .... 중략 (총 140개의 Color가 있으므로, 140줄의 코딩이 필요함 ^^;; ) .... ....
정말 난감하다.
초보개발자들은 저런상황에서,
"Color이름으로 색상리스트를 얻는 게 이런 방법밖에 없을까?"
"System.Drawing.Color구조체에 들어가 있는 색상들을 저렇게 하나하나 손으로 코딩하는게 아니라, 자동으로 추출해내는 방법이 없을까?"
라는 고민을 하게된다.
다행히도, 아니 당연하게도
그렇게 Color구조체로부터 이름 붙여진(Named) Color들을 추출해내는 것은 가능하다.
바로, 리플렉션(Reflection)이다.
리플렉션에 대해 자세히 알고 싶은 사람은, C#책을 꺼내보기 바라며,
리플렉션이 "클래스 또는 구조체 등의 내부 구조(프로퍼티,메소드 등)에 대한 정보를 가져오는 것"이라는 정도만 알아두길 바란다.
ArrayList colors = new ArrayList(); // System.Drawing.Color구조체의 Property들 중 public static인 것만 가져온다. PropertyInfo[] properties = typeof(Color).GetProperties(BindingFlags.Public
| BindingFlags.Static); // System.Drawing.Color구조체로부터 각각의 Color들을 추출하여 ArrayList에 담는다. foreach (PropertyInfo prop in properties) { Color color = (Color)prop.GetValue(null, null); if (color == Color.Transparent) continue; if (color == Color.Empty) continue; colors.Add (color); }

정말 간단하지 않은가?
public접근자에 static형인 프로퍼트들을 가져와서, Transparent와 Empty만 제외함으로써 모든 Named Color를 Color객체타입으로 얻어와 ArrayList에 담게 되는 것이다.
140줄의 코딩이 10줄도 안되는 코드로 대체가 되었다.
자, 여기서 만족할게 아니라, 한가지를 더 고민해보자.
위에서 우리가 구현한, "이름 붙여진 색상(Named Color)"의 리스트는 ABC순으로 정렬이 되어 있다.
당연히, 색상을 이름순으로 정렬하는 것보다는 색깔별(?)로 정렬하는 게 더 맞을 것이다.

이렇게 색깔별로 정렬하려면 어떻게 해야할까?
위에서 만든 ArrayList객체인 colors의 Sort메소드를 이용해보자.
"사용자정의 정렬"이므로 System.Collections.IComparer인터페이스를 상속받은 클래스를 직접 만들어보겠다.
// Color들을 정렬하기 위한 Sorter 클래스 정의
class ColorSorter: System.Collections.IComparer
{
// IComparer인터페이스를 상속받았으므로, Compare메소드를 구현해야한다.
// 색상의 Hue,Saturation,Brightness값을 비교해서,
// x<y이면 -1, x==y이면 0, x>y이면 1을 리턴하게된다.
public int Compare (object x, object y)
{
Color cx = (Color)x;
Color cy = (Color)y;
// Hue(색상)값을 추출한다.
float hx = cx.GetHue();
float hy = cy.GetHue();
// Saturation(채도)값을 추출한다.
float sx = cx.GetSaturation();
float sy = cy.GetSaturation();
// Brightness(명도)값을 추출한다.
float bx = cx.GetBrightness();
float by = cy.GetBrightness();
// 비교 우선순위
// 1 : Hue값을 가장 먼저 비교한다.
if (hx < hy) return -1;
else if (hx > hy) return 1;
else
{
// 2 : Hue값이 같은 경우 Saturation값을 비교한다.
if (sx < sy) return -1;
else if (sx > sy) return 1;
else
{
// 3 : Hue와 Saturation값이 모두 같은 경우
// Brightness값을 비교한다.
if (bx < by) return -1;
else if (bx > by) return 1;
else return 0;
}
}
}
}
이제 기존의 코드에 한 줄만 추가해주면 된다.
ArrayList colors = new ArrayList(); // System.Drawing.Color구조체의 Property들 중 public static인 것만 가져온다. PropertyInfo[] properties = typeof(Color).GetProperties(BindingFlags.Public
| BindingFlags.Static); // System.Drawing.Color구조체로부터 각각의 Color들을 추출하여 ArrayList에 담는다. foreach (PropertyInfo prop in properties) { Color color = (Color)prop.GetValue(null, null); if (color == Color.Transparent) continue; if (color == Color.Empty) continue; colors.Add (color); } colors.Sort(new ColorSorter());
정리
지금까지 "정렬된 Named Color의 리스트를 얻어오는 것"에 대해 알아보았다.
"리플렉션"에 대해 잘 모르는 초보개발자들이 많지만, 이 Article을 통해 Reflection이 얼마나 유익하게 사용되는 가를 느낄 수 있었을 것이다.
또한, IComparer인터페이스를 구현함으로써 "사용자정의 정렬"을 구현하는 로직에 대해 다시한번 되새겨볼 필요가 있다.
※ 구현환경
운영체제 : Microsoft Windows XP SP2
개발환경 : Visual Studio.NET 2003
.NET Framework 1.1 sp1
※ 필자소개
박 현 웅
- Office 2003 : Visual Studio Tools for Office Sy... (0)2007/02/05
- 웹 서비스의 세계로 - 구글 검색을 활용해보자. (0)2007/02/05
- 정렬된 Named Color List 만들기 (0)2007/02/05
- 여러가지 윈도우 시스템 제어 (2)2007/02/05
- 사용자 정의 Collection 클래스 만들기 (0)2007/02/05

수안이의 컴퓨터 연구실



Leave your greetings.