C# 기초 정리: 일반화 프로그래밍

일반화 프로그래밍(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();
    }
}