🌟 C# 제네릭(Generic)과 <T>😋 🌟
안녕하세요. 박민성입니다. ☺️
오늘은 C#의 제네릭(Generic)과 <T>에 대해서 글을 쓰고자 합니다. 🤔
제네릭은 Untiy 개발하면서 많이 사용하기 때문에 공부하여 글을 남기고자 합니다.
1. 제네릭이란?
제네릭은 타입을 미리 하나로 고정하지 않고 사용할 때 타입을 정할 수 있게 하는 기능입니다.
예를 들어서 일반 메서드라면
private void PrintInt(int val)
{
Debug.Log(val);
}
private void PrintString(string val)
{
Debug.Log(val);
}
타입마다 메서드를 따로 만들어야 합니다.
하지만.
제네릭을 사용하면
private void Print<T>(T val)
{
Debug.Log(val);
}
하나로 처리할 수 있습니다.
Print<int>(10);
Print<string>("Hello");
Print<float>(3.14f);
Print(10);
Print("Hello");
Print(3.14f);
호출은 이런식으로 호출합니다.
아래 코드는 위 코드에서 보통은 타입 추론이 가능하기 때문에 <>은 생략 가능합니다.
제네릭은 같은 로직을 여러 타입에 재사용할 수 있게 해주어
중복 코드를 줄이면서 타입 안전성을 유지하는 것이 제네릭을 사용하는 이유입니다.
2. <T>의 T는 정확히 뭘까요?
T는 타입 매개변수(Type Parameter)이라는 뜻입니다.
private void Print<T>(T val)
{
}
여기서 T는 아직 정해지지 않은 타입을 뜻합니다.
만약 Print<int>(10);을 작성하면 T는 int가 되고 Print<string>(10);을 작성하면 T는 string이 됩니다.
하지만 여기서 중요한점!!
T는 C# 키워드가 아닙니다. 그냥 예전부터 자리잡은 것 때문에 Type의 앞글자인 T를 많이 사용하지만
private void Print<MyType>(MyType val)
{
}
이런식으로 다르게 작성하여 사용할 수 있습니다.
3. 제네릭 메서드
private T GetValue<T>(T val)
{
return val;
}
이렇게 메서드 반환형을 T로 할 수 있습니다.
int number = GetValue(10);
string text = GetValue("Hello");
여기서 컴파일러가 전달된 값을 보고 T를 추론을 합니다.
GetValue(10)은 T가 int, GetValue("Hello")은 T가 string입니다.
private T GetFirst<T>(T[] array)
{
return array[0];
}
T는 매개변수 타입 뿐만 아니라 반환형, 지역 변수 타입 등 사용할 수 있습니다.
4. 제네릭 클래스
메서드뿐 아니라 클래스 자체도 제네릭으로 만들 수가 있습니다.
public class Box<T>
{
public T value;
}
사용할 때 타입을 결정하게 됩니다.
Box<int> intBox = new Box<int>();
intBox.value = 10;
Box<string> stringBox = new Box<string>();
stringBox.value = "Sword";
같은 Box<T> 클래스지만 Box<int>과 Box<string>은 서로 다른 구체 타입으로 취급됩니다.
5. List<T>, GetComponent<T>()
이게 제네릭이 사용된 예제입니다.
List<int> numbers = new List<int>();
실제로 List는 개념적으로 List<T> 형태의 제네릭 클래스입니다.

여기서 int를 넣었기 때문에 List<int>가 된 것입니다.
당연히
List<string> names;
List<GameObject> objects;
List<Enemy> enemies;
이런식으로 다른 타입도 가능합니다.
하나의 List<T> 구현을 여러 타입에 재사용하는 것입니다!
Unity의 GetComponent<T>()도 제네릭입니다.
Rigidbody rb = GetComponent<Rigidbody>();
Unity 개발하면서 이런식으로 컴포넌트를 GetComponent를 사용해서 가져오고 사용할 때가 많습니다.
GetComponent<T>()
GetComponent는 제네릭 메서드입니다.
Rigidbody rb = GetComponent<Rigidbody>(); // T가 Rigidbody로
BoxCollider collider = GetComponent<BoxCollider>(); // T가 BoxCollider로
가장 제네릭의 대표적인 사용 사례입니다.
6. 여러 타입 매개변수도 가능.
public class Pair<T1, T2>
{
public T1 first;
public T2 second;
}
이렇게 T를 2개를 사용할 수 있습니다. (단, 이름은 다르게)
Dictionary<TKey, TValue>
Dictionary가 이 사용 예제입니다. Dictionary<TKey, TValue> 는
TKey인 키 타입과 TValue인 값 타입 이 두개로 이루어져 있습니다.
7. 제네릭의 한계
T는 아무 타입이나 들어올 수 있기 때문에 컴파일러는 T가 어떤 기능을 가진지 모릅니다.
private void Attack<T>(T target)
{
target.TakeDamage(10);
}
이런식으로 사용하는 것은 불가능합니다.
왜냐하면 여기서 컴파일러는 아직 T 값이 무엇인지 모르기 때문입니다.
T는 int가 될 수도, string이 될 수도, Enemy가 될 수도 있기 때문입니다.
그렇기 때문에
where T : IDamageable
제네릭 제약조건을 걸 수가 있습니다. 이 주제는 다음에 다루도록 해보겠습니다.
오늘은 C#에 제네릭(Generic)과 <T>에 대해서 알아보았습니다.
제네릭은 정말 개발하면서 없으면 안되는 기능 중 하나인데여 두루두루 이곳저곳에서 많이 사용되는 것 같습니다.
제네릭 제약조건은 최대한 빠른 시일 내에 글을 작성해보도록 해보겠습니다.
오늘의 추천 노래는
GRIMACE
가사 내용보다 그냥 듣는 것이 즐겁습니다 ㅎㅎ
내일은 더욱 좋은 글을 써보도록 노력해보겠습니다.
봐주셔서 감사합니다. ☺️