Skip to main content

[This is C#] Chapter 11. 일반화 프로그래밍

이것이 C#이다 책을 읽고 공부한 노트입니다.




일반화 프로그래밍 #

  • 일반화(Generalization)
    • 공통된 개념을 찾아 묶는 것이다.



일반화 메소드 #

  • 일반화 메소드(Generic Method)
    • 데이터 형식을 일반화한 메소드이다.
    • 구체적인 형식대신 형식 매개변수(Type Parameter) 가 들어간다.
// 일반화 메소드. T는 형식 매개변수이다. 
void CopyArr<T>(T[] source, T[] target)
{
    for (int i = 0; i < source.Length; i++)
        target[i] = source[i];
}



일반화 클래스 #

  • 일반화 클래스(Generic Class)
    • 데이터 형식을 일반화한 클래스이다.
// 제네릭 클래스
class GenericArr<T>
{
    private T[] arr = new T[3];

    // 인덱서
    public T this[int idx]
    {
        get
        {
            return arr[idx];
        }

        set
        {
            if (idx >= arr.Length)
                Array.Resize<T>(ref arr, idx + 1);
            arr[idx] = value;
        }
    }
}


class MainApp
{
    static void Main(string[] args)
    {
        GenericArr<int> m = new GenericArr<int>();

        for (int i = 0; i < 5; i++)
            m[i] = i;

        for (int i = 0; i < 5; i++)
            Console.WriteLine($"{m[i]}");  // 0, 1, 2, 3, 4
    }
}



형식 매개변수 제약시키기 #

  • 형식 매개변수 T는 모든 데이터 형식을 대신할 수 있다.
    • 이것은 where절을 추가함으로써 제약시킬 수 있다.
제약 설명
where T : struct T는 값 형식이어야 한다.
where T : class T는 참조 형식이어야 한다.
where T : new() T는 반드시 매개변수가 없는 생성자가 있어야 한다.
where T : 기반 클래스 이름 T는 명시한 기반 클래스이거나 그의 파생 클래스여야 한다.
where T : 인터페이스 이름 T는 명시한 인터페이스를 구현해야한다. 여러 개의 인터페이스를 명시할 수도 있다.
where T : U TU로부터 상속받은 클래스여야한다.



일반화 컬렉션 #

  • System.Collections.Generic 네임스페이스는 다양한 일반화 컬렉션들을 담고 있다.
    • 일반화 컬렉션은 박싱과 언박싱같은 형식 변환이 매번 일어나지 않기 때문에 좋다.
용도 제네릭 논-제네릭
인덱스 별로 엑세스 List<T> Array, ArrayList
순서대로 액세스 LinkedList<T>
FIFO 방식으로 사용 Queue<T> Queue
LIFO 방식으로 사용 Stack<T> Stack
키/값 쌍으로 저장 Dictionary<TKey, TValue> Hashtable
추가, 삭제 시 알림 표시 ObservableCollection<T>
정렬된 컬렉션 SortedList<TKey, TValue> SortedList
수학 함수용 집합 HashSet<T>



foreach를 사용할 수 있는 일반화 클래스 #

  • IEnumerable<T>인터페이스를 구현하면 형식 변환 없이 일반화 클래스로 foreach를 사용할 수 있겠다.
    • IEnumerator GetEnumerator()
    • IEnumerator<T> GetEnumerator()
      • bool MoveNext()
      • void Reset()
      • object Current {get;}
      • T Currnet {get;}
class MyList<T> : IEnumerable<T>, IEnumerator<T>
{
    private T[] arr = new T[3];
    private int pos = -1;

    // 인덱서
    public T this[int idx]
    {
        get
        {
            return arr[idx];
        }

        set
        {
            if (idx >= arr.Length)
                Array.Resize<T>(ref arr, idx + 1);
            arr[idx] = value;
        }
    }

    // IEnumerator의 메소드 및 프로퍼티
    object IEnumerator.Current { get { return arr[pos]; } }
    public T Current { get { return arr[pos]; } }

    public bool MoveNext()
    {
        if (pos == arr.Length - 1)
        {
            Reset();
            return false;
        }

        pos++;
        return (pos < arr.Length);
    }

    public void Reset()
    {
        pos = -1;
    }

    // IEnumerable의 메소드
    IEnumerator IEnumerable.GetEnumerator()
    {
        return this;
    }

    public IEnumerator<T> GetEnumerator()
    {
        return this;
    }

    public void Dispose()
    {
        //...
    }
}

class MainApp
{
    static void Main(string[] args)
    {
        MyList<int> m = new MyList<int>();

        for (int i = 0; i < 5; i++)
            m[i] = i;

        // foreach문이 가능!
        foreach (int number in m)
            Console.WriteLine($"{ number }");  // 0, 1, 2, 3, 4
    }
}