9. 컬렉션
일반화
어떤 특수한 개념으로부터 공통된 개념을 찾아 묶는 것을 말한다.
일반화 프로그래밍이 일반화 하는 대상은 데이터 형식(Type)이다.
일반화 메소드
이름처럼 데이터 형식을 일반화한 메소드.
선언을 하는 방법은 다음과 같다.
한정자 반환형식 메소드명<형식매개 변수>(매개 변수)
{
}
다음 예제는 내용은 같지만 두개의 메소드로 분리가 되어있다.
이것을 일반화 메소드를 사용해서 하나로 합친 후 확장성을 넓힐 수 있다.
굳이 데이터 형식마다 메소드를 오버로딩 할 필요가 없어지게 된다.
void CopyData(int data1, int data2)
{
data1 = data2;
}
void CopyData(double data1, double data2)
{
data1 = data2;
}
위 코드에서 데이터 형식 부분을 T 기호로 치환을 한다. T는 Type을 뜻한다.
void CopyData<T> (T data1, T data2)
{
data1 = data2;
}
T는 C#이 지원하는 데이터 형식이 아니다. 따라서 원래 위 코드를 실행하면 컴파일 오류가 나야 한다.
오류가 나지 않기 위해서는 T가 어떤 형식인지 알려줘야 한다.
그래서 메소드 이름 뒤에 <> 괄호 사이에 T를 넣으면 T가 형식 매개 변수가 된다.
따라서 이 메소드를 호출할 때 T부분에 형식 이름을 입력해주면 컴파일러가 메소드의 나머지 부분도
해당 데이터 형식으로 치환을 해준다.
int sc = 10;
int tg = 30;
CopyData<int>(sc, tg);
위 예제는 일반화 메소드가 어떤 것인지 알려주기 위해 임의로 작성한 거라 실제로 작성을 해보면
Copy가 제대로 안되어서 sc의 값이 변경이 안된다.
일반화 클래스
일반화 클래스의 선언 방법은 다음과 같다.
class 클래스명 <형식매개변수>
{
}
일반화 클래스도 일반화 메소드와 비슷하게 내용은 똑같지만 데이터 타입만 다른 경우
클래스를 하나로 묶어 확장성을 좋게 할 수 있다.
class Test_Generic<T>
{
private T data;
public T GetData(){return data;}
}
형식 매개 변수 제약시키기
일반화의 형식 매개 변수 T는 모든 데이터 형식을 대신할 수 있다.
하지만 가끔 조건을 갖춘 형식에만 대응하는 형식 매개 변수가 필요할 때도 있다.
이 때 형식 매개 변수 조건에 제약을 걸 수가 있다.
예를 들면 다음처럼 형식 매개 변수 T에 Test로부터 상속받는 형식이어야 할 것이라는 제약을 줄 수 있다.
class TestGeneric<T> where T : Test
{
}
다음 표가 where 절과 함께 사용할 수 있는 제약 조건이다.
where T : struct | T는 값 형식 |
where T : class | T는 참조 형식 |
where T : new() | T는 반드시 매개 변수가 없는 생성자 |
where T : 기반클래스명 | T는 기반 클래스의 파생클래스 |
where T : 인터페이스명 | T는 명시한 인터페이스를 반드시 구현 |
where T : U | T는 또 다른 형식 매개 변수 U로부터 상속받은 클래스 |
일반화 컬렉션
기존의 컬렉션들은 모두 object 형식을 기반으로 했다. 그래서 int, string 등의 데이터와 객체도 담을 수 있었다.
object 형식을 기반으로 하기 때문에 성능 문제를 갖고 있다. 요소에 접근할 때 마다 형식 변환이 계속 일어나기 때문
반면 일반화 컬렉션은 이런 성능 문제를 해결할 수 있다.
컴파일할 때 컬렉션에서 사용할 형식이 결정되고
쓸데없는 형식 변환을 일으키지 않는다.
잘못된 형식의 객체를 담게 될 위험도 피할 수 있다.
일반화 컬렉션을 사용하기 위해서는 using 문으로 선언을 하면 된다.
using System.Collections.Generic
일반화 컬렉션의 종류로는 List<T> Queue<T> Stack<T> Dictionary<TKEY, TVALUE> 등이 있다.
각각 ArrayList, Queue, Stack, Hashtable을 일반화 한 것이다.
List<T>
ArrayList와 사용방법은 동일하다.
차이점은 List<T>는 형식 매개 변수로 입력한 형식 외에는 입력을 허용하지 않는 것이다.
List<int> intList = new List<int>();
intList.Add(1);
intList.Add(2);
intList.Add(3);
foreach(int i in intList)
Console.WriteLine("{0}", i);
List<string> stringList = new List<string>();
stringList.Add("Hello");
stringList.Add("Hi");
foreach(string i in stringList)
Console.WriteLine("{0}", i);
Queue<T>
기존 Queue와 사용 방법 동일하다.
Queue<int> q = new Queue<int>();
queue.Enqueue(1);
queue.Enqueue(2);
queue.Enqueue(3);
queue.Enqueue(4);
queue.Enqueue(5);
while(q.Count > 0)
Console.Write(q.Dequeue());
Stack<T>
스택도 동일..
Stack<int> st = new Stack<int>();
st.Push(1);
st.Push(2);
st.Push(3);
st.Push(4);
st.Push(5);
while(st.Count > 0)
Console.WriteLine(st.Pop());
Dicitionary<T>
Hashtable과 동일
Dictionary<string, string> dic = new Dictionary<string, string>();
dic["Test"] = "TestHello";
dic["Hello"] = "HelloTest";
Console.WrieLine(dic["Test"]);