Table of Content
일반화 프로그래밍(Generic Programming)
- 처리하는 로직은 같지만 형식이 다른 객체를 입력받아 처리하는 코드 작성 시 오버로딩하지않고 모든 형식을 지원하도록 프로그래밍
- 형식 매개변수(Type Parameter), 를 사용
class Program { /* 제네릭 메소드(Generic Method) */ static void CopyArray<T>(T[] source, T[] target) { for (int i = 0; i < source.Length; i++) target[i] = source[i]; } public static void Main(string[] args) { int[] int_source = new int[] { 1, 2, 3, 4, 5 }; int[] int_target = new int[int_source.Length]; CopyArray<int>(int_source, int_target); // 형식 매개변수로 int를 넘김 Console.Write("# int_target 출력: "); foreach (int i in int_target) Console.Write("{0} ", i); Console.WriteLine(); double[] double_source = new double[] { 1.1, 2.2, 3.3, 4.4, 5.5 }; double[] double_target = new double[double_source.Length]; CopyArray<double>(double_source, double_target); // 형식 매개변수로 double을 넘김 Console.Write("# double_target 출력: "); foreach (double d in double_target) Console.Write("{0} ", d); Console.WriteLine(); } }
일반화 클래스(Generic Class)
/* 일반화 클래스(Generic Class) */ class MyList<T> { private T[] array; public MyList() { array = new T[3]; } /* 프로퍼티 */ public int Length { get { return array.Length; } } /* 인덱서 */ public T this[int index] { get { return array[index]; } set { if (index >= array.Length) Array.Resize<T>(ref array, index + 1); array[index] = value; } } } class Program { public static void Main(string[] args) { MyList<int> int_list = new MyList<int>(); for (int i = 0; i < 10; i++) int_list[i] = i; Console.Write("# int_list 출력: "); for (int i = 0; i < 10; i++) Console.WriteLine(int_list[i]); Console.WriteLine(); MyList<string> string_list = new MyList<string>(); string_list[0] = "안녕요?ㅎ"; string_list[1] = "C#"; string_list[2] = "프로그래밍"; string_list[3] = "짱 재밌자너~"; Console.WriteLine("# string_list 출력: "); for (int i = 0; i < string_list.Length; i++) Console.WriteLine(string_list[i]); } }
일반화 프로그래밍의 형식 매개변수 제약
- 특정 매개변수를 받도록 제약하기 위해 클래스 선언문 헤더에 where 절 추가
class MyClass { } interface MyInterface { } /* 형식 매개변수 제약조건 */ class GenericClass_1<T> where T : MyClass { } // MyClass(임의의 클래스)로부터 상속받는 형식이어야 함 class GenericClass_2<T> where T : struct { } // 값 형식이어야 함 class GenericClass_3<T> where T : class { } // 참조 형식어야 함 class GenericClass_4<T> where T : new() { } // 매개변수가 없는 생성자가 있어야 함 class GenericClass_5<T> where T : MyInterface { } // MyInterface(임의의 인터페이스)로부터 상속받는 형식이어야 함
일반화 컬렉션(Generic Collection)
- ArrayList, Stack, Queue, Hashtable 등은 object 형식 기반
- 어떤 형식의 객체도 담을 수 있음
- 그러나 형식 변환이 자주 일어나 성능 문제가 발생할 수 있음
- 일반화 컬렉션은 위의 문제를 해결
- 컬렉션에서 사용할 형식이 결정되므로 쓸데없는 형식 변환이 일어나지 않음
- 잘못된 형식의 객체 삽입 방지
- 종류: List, Queue, Stack, Dictionary 등
class Program { public static void Main(string[] args) { /* List<T>: ArrayList와 같은 기능 */ List<char> list = new List<char>(); list.Add('a'); list.Add('b'); list.Add('c'); list.Add('d'); list.Add('e'); list.RemoveAt(2); list.Insert(2, 'C'); Console.Write("# list 출력: "); foreach (char c in list) Console.Write("{0} ", c); Console.WriteLine(); /* Queue<T>: Queue와 같은 기능 */ Queue<int> queue = new Queue<int>(); for (int i = 0; i < 5; i++) queue.Enqueue(i); Console.Write("# queue 출력: "); while (queue.Count > 0) Console.Write("{0} ", queue.Dequeue()); Console.WriteLine(); /* Stack<T>: Stack과 같은 기능 */ Stack<double> stack = new Stack<double>(); for (int i = 0; i < 5; i++) stack.Push(i + 0.5); Console.Write("# stack 출력: "); while (stack.Count > 0) Console.Write("{0} ", stack.Pop()); Console.WriteLine(); /* Dictionary<TKey, TValue>: Hashtable의 일반화 버전 */ Dictionary<string, string> dic = new Dictionary<string, string>(); dic["C#"] = "씨샵"; dic["Programming"] = "프로그래밍"; dic["Funny"] = "넘 재밌자너~"; Console.Write("# dic 출력: "); Console.Write("{0} ", dic["C#"]); Console.Write("{0} ", dic["Programming"]); Console.Write("{0} ", dic["Funny"]); Console.WriteLine(); } }