카테고리 없음

🌟 C# 제네릭(Generic)과 <T>😋 🌟

minsoungdev 2026. 8. 12. 10:23

안녕하세요. 박민성입니다. ☺️

 

오늘은 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> 형태의 제네릭 클래스입니다.

List를 F12로 들어갔을때

여기서 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

가사 내용보다 그냥 듣는 것이 즐겁습니다 ㅎㅎ

 

내일은 더욱 좋은 글을 써보도록 노력해보겠습니다. 

봐주셔서 감사합니다. ☺️