목차
Reflection과 Attribue를 공부하다가 이것저것 더 알아보게 되었다.
1. Type이란?
게임에서 몬스터를 만든다고 가정해 보자. 우리는 다음과 같은 코드로 몬스터를 만든다.
Monster A = new Monster();
이때 생성된 A는 메모리 공간을 차지하고 살아 숨 쉬는 '객체(Instance)'이다.
그렇다면 이 객체를 만들어내기 위한 설계도(Type)란 정확히 무엇일까?
① 모든 것은 '메타데이터(Metadata)'로 기록된다
C#에서 코드를 작성하고 컴파일(빌드)을 하면, 컴퓨터는 소스 코드를 기계어로 번역함과 동시에 메타데이터(Metadata)'라는 거대한 정보 사전을 만들어낸다. 이 메타데이터 안에는 프로그램에 존재하는 모든 클래스, 구조체, 인터페이스, 열거형(Enum) 등의 이름, 변수(Field), 함수(Method), 상속 관계가 빠짐없이 기록된다. 즉, C#에서 말하는 Type이란 컴파일러가 만들어낸 이 메타데이터(설계도) 정보를 프로그램이 실행되는 중(런타임)에 코드로 읽고 다룰 수 있도록 객체화해 놓은 것을 의미한다.
② 100마리의 몬스터, 단 1개의 설계도
만약 new Monster()를 100번 호출해서 100마리의 몬스터 객체를 만들었다고 해보자. 메모리에는 100개의 몬스터 실체가 올라가지만, 설계도(Type 객체)는 메모리에 단 1개만 존재한다. 100마리의 몬스터는 모두 이 유일한 원본 설계도 하나를 함께 가리키고(참조하고) 있는 형태다.
③ C#의 모든 것은 Type을 가진다
그렇다면 특정 클래스나 구조체만 설계도를 가질까? 그렇지 않다. C#은 '강한 타입(Strongly typed) 언어'이기 때문에, 복잡한 클래스는 물론 int나 float 같은 기본 자료형까지 C#에 존재하는 모든 데이터는 반드시 자신의 Type을 가져야만 한다. 이를 시스템적으로 보장하기 위해 C#의 모든 데이터는 System.Object라는 최고 조상으로부터 파생되도록 설계되었다. 그리고 이 Object 클래스 안에는 자신의 원본 설계도를 찾아 반환해 주는 GetType()이라는 기능이 기본적으로 내장되어 있다.
결과적으로 C#의 모든 것들은 "너의 설계도가 무엇이냐?"라는 질문을 받았을 때, 언제든지 System.Type 객체를 꺼내어 대답할 수 있는 능력을 갖추고 있는 것이다.
https://learn.microsoft.com/ko-kr/dotnet/api/system.type?view=net-8.0
Type 클래스 (System)
클래스 형식, 인터페이스 형식, 배열 형식, 값 형식, 열거형 형식, 형식 매개 변수, 제네릭 형식 정의 및 개방형 생성 제네릭 형식이나 폐쇄형 생성 제네릭 형식에 대한 형식 선언을 나타냅니다.
learn.microsoft.com
https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/types/
Learn the fundamentals of the C# type system - C#
Learn about creating types in C#, such as tuples, records, value types, and reference types. Learn to choose between these options.
learn.microsoft.com
2. 설계도 읽기
두 가지 방법으로 설계도를 읽을 수 있다.
1. typeof(클래스명) : 대상을 정확히 알고 있을 때 (컴파일 타임)
객체를 직접 생성하지 않고, 클래스의 이름만으로 설계도를 바로 가져오고 싶을 때 사용,
코드를 작성하는 시점에 대상이 무엇인지 명확하게 알고 있을 때 주로 쓰임.
// 인스턴스 없이, Player 클래스 자체의 설계도를 바로 가져옵니다.
Type playerType = typeof(Player);
2. 변수.GetType() : 대상의 진짜 정체를 모를 때 (런타임)
눈앞에 생성된 실체(인스턴스)가 정확히 어떤 클래스로 만들어졌는지 모를 때,
그 객체에게 직접 "너의 설계도를 줘!"라고 요청하는 방법.
// target이 오크인지 고블린인지 모를 때, 실제 생성된 객체의 설계도를 뽑아옵니다.
public void Attack(object target)
{
Type targetType = target.GetType();
}
3. 궁금했던 점
Q1. C#에서 말하는 Type은 정확히 무엇인가요? 작성한 코드 자체와 같은 건가요? A. 그렇지 않습니다. Type은 코드도, 메모리에 올라간 실제 데이터(인스턴스)도 아닙니다. 비유하자면 '클래스의 설계 사양서' 또는 **'목차'**와 같습니다.
- 포함되는 정보 (메타데이터): 클래스의 이름, 가지고 있는 변수명과 데이터 타입(int, string 등), 함수의 이름과 매개변수 구조 등 껍데기 정보.
- 포함되지 않는 정보: 변수에 들어있는 실제 값(예: hp가 100인지 50인지), 함수의 내부 실행 로직, 특정 객체의 메모리 주소 등.
Q2. Type에 객체의 실제 값이 없다면, 유니티 인스펙터 창에서는 어떻게 변수 값을 보여주고 수정할 수 있는 건가요? A. 유니티 에디터는 **Type(설계도)**과 Instance(실제 객체) 두 가지를 모두 활용하여 인스펙터를 구성합니다. (리플렉션 및 직렬화 과정)
- UI 생성 (Type 활용): C# 스크립트의 Type 정보를 읽어와 "어떤 타입의 변수들이 있는지" 파악하고, 그에 맞는 입력칸(UI)을 화면에 그립니다.
- 값 갱신 (Instance 활용): 화면에 띄울 빈칸을 만든 후, 현재 씬에서 선택된 실제 게임 오브젝트(Instance)의 메모리에 직접 접근하여 현재 값을 읽어와 빈칸을 채웁니다. 인스펙터에서 값을 수정하면 에디터가 다시 해당 메모리 주소로 찾아가 값을 덮어씌웁니다.
Q3. GetComponent<T>()는 내부적으로 typeof를 사용한다고 했는데, 그럼 검색 비용이 드는 건가요? 씬 전체를 뒤지는 건가요? A. 네, 명백하게 무거운 검색 비용이 발생합니다.
- typeof(T)와의 차이: typeof(T) 자체는 단순히 메모리에 있는 Type 사양서를 가리키는 명령어라 비용이 거의 없습니다. 하지만 GetComponent<T>()는 이 Type 정보를 '검색 키워드'로 사용하여 실제 일치하는 컴포넌트를 찾아내는 '동작'입니다.
- 검색 범위와 과정: 씬 전체가 아닌 해당 게임 오브젝트 내부에서만 검색합니다. 오브젝트가 가진 컴포넌트 배열을 순회하며, C++ 코어 엔진과 C# 환경을 오가면서 각 컴포넌트의 Type이 요청한 Type과 일치하는지 일일이 대조합니다.
- 결론: 이 과정에서 CPU 자원이 소모되므로, Update() 같은 반복 함수에서 매 프레임 호출하면 프레임 드랍의 원인이 됩니다. 반드시 Start()나 Awake()에서 한 번만 호출하여 변수에 캐싱(저장)해 두고 사용해야 합니다.
'개념공부' 카테고리의 다른 글
| Reflection (0) | 2026.03.26 |
|---|---|
| C# 프로퍼티(Property) (0) | 2026.03.14 |
| 동기와 비동기 (0) | 2026.03.12 |
| Delegate,Action,Event,UnityEvent (0) | 2026.03.04 |
| 동적 계획법 (Dynamic Programming, DP) (0) | 2025.03.19 |