1. 제네릭(Generic)이란?
- 데이터 형식을 일반화하여 사용이 가능하게 한 형식 매개변수(Type parameter)이다.
- 박싱/언박싱(강제 형번환)이 일어나지 않도록 타입을 미리 지정하는 방식이다.
2. 제네릭의 장점
- 지정된 타입과 호환하는 타입에 대해서만 사용할 수 있게하고, 그렇지 않은 경우 컴파일 에러를 발생시켜 타입에 대한 안정성이 높다.
- 런타임 시 데이터 형식이 결정 되는 것이 아닌 코드에서 호출할 때 데이터 형식이 결정되므로 성능 저하가 없다.
- 또한 Object 타입을 이용해 값 타입을 사용한 경우 박싱이나 언박싱이 일어나는데 제네릭을 사용하면 값 타입의 인스턴스 자체를 값 자체로 전달할 수 있어 박싱이 수행되지 않아 성능이 더 좋다.
- 컴파일러가 형변환을 해주기 때문에 개발자가 편리하고, 컴파일 시 타입을 체크하여 에러를 사전에 발견할 수 있다.
- 보통 <T>를 사용하며, 어떤 것을 담아 놓을 컨테이너 역할을 한다.
- 코드의 재사용성을 높일 수 있다.
class Program
{
static void PrintInt(int i)
{
Console.WriteLine(i); // int형만 출력
}
static void PrintString(string s)
{
Console.WriteLine(s); // string형만 출력
}
static void PrintGeneric<T>(T g)
{
Console.WriteLine(g); // 받아온 타입에 따라 출력
}
static void Main(string[] args)
{
PrintInt(111);
PrintInt("abc"); // -> 오류
PrintString("abc");
PrintString(111); // -> 오류
PrintGeneric<int>(111);
PrintGeneric<string>("abc");
}
}
2. 제네릭 클래스
- c#에서는 기본적으로 제공하는 제네릭 클래스가 많다.
- 대표적으로는 List<T>, Dictionary<T>, LinkedList<T>
static void Main(string[] args)
{
// List<T> 사용 - 타입을 미리 지정하여 안정성을 높임
List<int> intList = new List<int>();
intList.Add(1);
intList.Add("s"); // -> 에러
}
3. 제네릭 타입 제약
- [where T : 제약조건] 을 제네릭 선언 후 붙여준다.
class Program
{
static void PrintValue<T>(T val) where T : struct // 값형으로 제네릭 타입을 제한
{
Console.WriteLine(val);
}
static void PrintReference<T>(T refer) where T : class // 참조형으로 제네릭 타입을 제한
{
Console.WriteLine(refer);
}
static void Main(string[] args)
{
PrintValue<int>(111);
PrintValue<string>("abc"); // -> 오류 : 참조형이기 때문
PrintReference<int>(111); // -> 오류 : 값형이기 때문
PrintReference<string>("abc");
}
}
4. 제네릭 메서드
- 매개변수의 타입을 미리 결정하지 않고 사용시 결정하기 위한 것
class Program
{
static void Main(string[] args)
{
int a = 3;
int b = 4;
string c = "c";
string d = "d";
SwapInt(ref a, ref b);
SwapInt(ref c, ref d); // -> 오류 : int형이 아니기 때문
SwapString(ref a, ref b); // -> 오류 : string형이 아니기 때문
SwapString(ref c, ref d);
// 제네릭 이용 -> 사용하면서 타입이 결정됨
Swap(ref a, ref b); // int형 swap
Swap(ref c, ref d); // string형 swap
Swap(ref a, ref c); // -> 오류 : 두 매개변수의 형이 다르기 때문
}
public static void SwapInt(ref int a, ref int b)
{
int temp = a;
a = b;
b = temp;
}
public static void SwapString(ref string a, ref string b)
{
string temp = a;
a = b;
b = temp;
}
// 제네릭 메소드
public static void Swap<T>(ref T a, ref T b)
{
T temp = a;
a = b;
b = temp;
}
}
<면접 예시 답안>
제네릭이란 데이터 형식을 일반화하여 사용가능하게 만든 형식 매개변수이며, 형변환시 타입을 미리 지정해 박싱, 언박싱이 일어나지 않도록 하여 안정성과 성능을 높이는 방식입니다.