제네릭이 없다면 기본 형식(primitive types)은 Object 타입으로 박싱/언박싱을 거쳐야 해서 성능 상 문제가 발생한다. 이를 해결하기 위해 닷넷 프레임워크 2.0에서는 제네릭을 도입했다.
CLR은 JIT 컴파일 시 클래스가 타입에 따라 정의될 때마다 T에 대응되는 타입을 대체해서 확장한다.
T에 int와 double을 전달한 코드가 사용된다면 와 에 해당하는 2개의 클래스에 해당하는 기계어 코드가 자동으로 만들어진다.
class 클래스명<형식매개변수>
✍ 샘플 코드
class Test
{
static void Main(string[] args)
{
MyStack<int> intStack = new MyStack<int>(5);
intStack.Push(1);
intStack.Push(2);
intStack.Push(3);
Console.WriteLine(intStack.Pop());
Console.WriteLine(intStack.Pop());
Console.WriteLine(intStack.Pop());
MyStack<string> stringStack = new MyStack<string>(5);
stringStack.Push("a");
stringStack.Push("b");
stringStack.Push("c");
Console.WriteLine(stringStack.Pop());
Console.WriteLine(stringStack.Pop());
Console.WriteLine(stringStack.Pop());
}
}
class MyStack<T>
{
T[] list;
int pos;
public MyStack(int size)
{
list = new T[size];
}
public void Push(T item)
{
list[pos] = item;
pos++;
}
public T Pop()
{
pos--;
return list[pos];
}
}
✅ 결과
3
2
1
c
b
a
형식 매개변수 이름은 임의로 정할 수 있다.
✍ 샘플코드
class MyStack<myType>
{
myType[] list;
int pos;
public MyStack(int size)
{
list = new myType[size];
}
public void Push(myType item)
{
list[pos] = item;
pos++;
}
public myType Pop()
{
pos--;
return list[pos];
}
}
2개 이상의 형식 매개변수를 지정하는 것도 가능하다.
✍ 샘플 코드
class MyMap<K, V>
{
K _key;
V _value;
public void Set(K key, V value)
{
_key = key;
_value = value;
}
}
형식매개변수가 클래스 수준이 아닌 메서드 수준에서 부여될 수도 있다.
[접근제한자] 반환타입 메서드명<형식매개변수>(타입명 매개변수명)
호출 시에는 제네릭 타입을 명시하지 않아도 컴파일러가 매개변수를 보고 타입을 유추하여 처리해준다.
✍ 샘플코드
static void Main(string[] args)
{
print(true);
print(123);
print("hihi");
print<bool>(false);
print<int>(321);
print("byebye");
}
static void print<T>(T item)
{
Console.WriteLine(item);
}
✅ 결과
True
123
hihi
False
321
byebye