bdfgdfg

[C#] 일반화(제네릭) 프로그래밍 본문

게임프로그래밍/C#

[C#] 일반화(제네릭) 프로그래밍

marmelo12 2022. 4. 21. 17:51
반응형

일반화(제네릭)이란 데이터 형식에 의존되지 않은 것을 의미한다.

 -> C++의 템플릿과 유사하다.

 

예로들어 단순하게 static함수에서 배열의 요소를 복사하는 함수 하나를 만들었다고 보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Program
{
    static void CopyArray(int[] source, int[] target)
    {
        for (int push = 0; push < target.Length; ++push)
            source[push] = target[push];
    }
    static void Main(string[] args)
    {
        int[] source = new int[10];
        int[] target = new int[10];
        for (int i = 0; i < target.Length; ++i)
            target[i] = i + 1;
 
        CopyArray(source, target);
 
        foreach(int score in source)
            Console.WriteLine(score);
 
    }
}
 
cs

위 함수는 잘 동작한다.

하지만 아쉬운게 있다. 만약 복사할 배열의 자료형이 int형이 아니라면? 함수 오버로딩을 통해 여러개의 CopyArray함수를 만들어야 한다.

이러한 문제를 해결하기 위한 것이 제네릭.

제네릭은 함수,클래스등에 적용이 가능하다.

사용 방법은 간단하다.

함수이름 오른쪽에 <형식 매개 변수>만 선언하면 해당 함수는 제네릭 메소드가 된다.

 -> C++의 함수 템플릿처럼

또한 호출시점에서 해당 형식 매개 변수의 타입을 넘겨주면 된다.

이렇게 한다면 컴파일러는 컴파일 시 T에 우리가 넣은 형식 매개 변수(타입)을 넣어서 치환한다.

 

제네릭 클래스

제네릭 클래스도 사용방법이 똑같다.

이전 시간에 인덱서를 공부하면서 MyList라는 가변 배열 클래스를 만들었다.

해당 클래스의 문제는 int형 자료형만 지원했다. 만약 제네릭이 없었다면 일일히 하나하나 똑같이 복사해서 만들어줘야 했겠지만 제네릭을 통해서 그럴 필요가 없어진다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
class MyList<T> : IEnumerable, IEnumerator
{
    private T[] m_arr = new T[2];
    private int m_size = 0;
    private int m_capacity = 2;
 
    private int m_pos = -1// 순회를 하기 위해 필요.
 
    //IEnumerator 멤버
    //Current 프로퍼티는 현재 위치의 요소를 반환한다.
    public object Current
    {
        get
        {
            return m_arr[m_pos];
        }
    }
 
    // IEnumerator 멤버
    // 다음 위치의 요소로 이동
    public bool MoveNext()
    {
        if (m_pos == m_size - 1)
        {
            Reset();
            return false;
        }
 
        m_pos++;
        return m_pos < m_size;
    }
    // IEnumerator 멤버 
    //  위치를가리키는 pso를 첫 요소의 '앞'으로 옮긴다.
    public void Reset()
    {
        m_pos = -1;
    }
    // IEnumerable 멤버
    public IEnumerator GetEnumerator()
    {
        for (int i = 0; i < m_size; ++i)
            yield return m_arr[i];
    }
 
 
    public void Push_Back(T item)
    {
        if(m_size >= m_capacity)
        {
            m_capacity = m_capacity * 2;
            T[] tempArr = new T[m_capacity];
            int push = 0;
            for (; push < m_size; ++push)
                tempArr[push] = m_arr[push];
            tempArr[push] = item;
            m_arr = tempArr;
            ++m_size;
        }
        else
        {
            m_arr[m_size++= item;
        }
    }
    public T Pop_Back()
    {
        return m_arr[--m_size];
    }
 
    // 인덱서 프로퍼티와 똑같다. 다만 이름을 this로 해야한다.
    // 대괄호 안의 인덱스명은 아무거나 해도 상관없다.
    public T this[int index]
    {
        get
        {
            Debug.Assert(index <= m_size); // 해당조건이 거짓이면 프로그램은 중단된다.
            return m_arr[index];
        }
    }
 
}
 
cs

말 그대로 일반화 시켰기에 자료형에 의존하지 않고 여러 타입에 대응되는 클래스가 된 것.

 

제네릭 메소드나 제네릭 클래스에 대응되는 형식 매개 변수 T는 모든 데이터 형식을 대신할 수 있다.

다만 종종 특정 조건을 갖춘 형식에만 대응하는 형식 매개 변수(T)가 필요할 때도 있다.

 -> 여기서 형식 매개 변수의 조건에 제약을 줄 수 있다.

1
2
3
4
5
6
7
8
 // 형식 매개 변수 T는 '값' 형식이어야 한다는 제약을 주었다.
 // where 형식 매개 변수 : 제약조건
 static void CopyArray<T>(T[] source, T[] target) where T : struct
 {
     for (int push = 0; push < target.Length; ++push)
         source[push] = target[push];
 }
 
cs

조금 특이한데 제약조건은 where절과 사용할 수 있도록 여러 제약이 이미 정해져있다.

제약 설명
where T : struct T는 값 형식이어야 한다는 제약조건.
where T : class T는 참조 형식이어야 한다는 제약조건.
where T : new() T는 반드시 매개 변수가 없는 생성자가 있어야 한다는 제약 조건.
where T : 기반 클래스 이름 T는 명시한 기반 클래스의 파생 클래스여야 한다는 제약 조건
where T : 인터페이스 이름 T는 명시한 인터페이스를 반드시 구현하고 인터페이스 이름에는 여러개의 인터페이스를 명시할 수 있다.
where T : U T는 또 다른 형식 매개 변수 U로부터 상속받은 클래스여야 한다.

 

일반화 컬렉션

System.Collections.Generic 넴이스페이스는 다양한 컬렉션 클래스를 담고 있다.

주요하게 봐야할것은 다음 5가지.

1. List<T> : 가변배열 제네릭 클래스.

2. LinkedList<T> : 이중 연결 리스트 제네릭 클래스

3. Queue<T> : 자료구조 큐.(FIFO) 제네릭 클래스

4. Stack<T> : 자료구조 스택.(LIFO) 제네릭 클래스.

5. Dictionary<TKey,TValue> : 자료구조 해시 테이블. 제네릭 클래스

 

딕셔너리의 경우에는

https://ponyozzang.tistory.com/325

등 다양하게 참고하자. 익숙해지는게 중요

반응형

'게임프로그래밍 > C#' 카테고리의 다른 글

Linq - Group by  (0) 2022.11.05
[C#] 예외처리(try-catch)  (0) 2022.04.22
[C#] 인덱서(Indexer)  (0) 2022.04.21
[C#] 프로퍼티(갓)  (0) 2022.04.19
[C#] 인터페이스,추상클래스  (0) 2022.04.19
Comments