전체코드
using System.ComponentModel;
using System.Numerics;
using System.Threading;
using System.Collections.Generic;
using CSharp;
using System.Reflection;
namespace CSharp
{
class Program
{
class Important : System.Attribute
{
String message;
public Important(string message)
{
this.message = message;
}
}
class Monster
{
[Important("very important")]
public int hp;
protected int attack;
private float speed;
void Attack() { }
}
static void Main(string[] args)
{
Monster monster = new Monster();
Type type = monster.GetType();
var fields = type.GetFields(System.Reflection.BindingFlags.Public
| System.Reflection.BindingFlags.NonPublic
| System.Reflection.BindingFlags.Static
| System.Reflection.BindingFlags.Instance);
foreach(FieldInfo field in fields)
{
string access = "protected";
if (field.IsPublic) access = "public";
else if (field.IsPrivate) access = "private";
var Attribute = field.GetCustomAttributes();
Console.WriteLine($"{access}{field.FieldType.Name}{field.Name}");
}
}
}
}
📖 Reflection(리플렉션)이란?
"C# 객체의 내부 정보를 X-Ray 찍듯이 런타임 중에 들여다보고, 분석하고, 심지어 조작까지 가능하게 해주는 기능"
💥 Reflection이 왜 필요할까?
1️⃣ 타입 정보 탐색
- 어떤 객체인지 이름, 필드, 메서드, 이벤트 등 모든 정보를 런타임에 확인 가능
- 컴파일 시점이 아닌, 실행 중에 동적 확인 및 처리
2️⃣ 동적 호출
- 메서드 이름만 문자열로 받아서, 그 메서드를 실행하고 싶을 때 사용
- (예: 테스트 자동화 프레임워크가 테스트 메서드들 동적 호출)
3️⃣ 유니티 개발에서도 중요
Inspector 창에서 private 멤버도 보이게 하는 [SerializedField] 같은 기능도 Reflection 기반
- 런타임 중에 오브젝트 정보를 파악하는 디버깅 도구 제작에도 활용
📐 기본 예제 분석 - Monster 클래스와 Reflection 활용
using System;
using System.Reflection;
namespace CSharp
{
class Program
{
class Monster
{
public int hp;
protected int attack;
private float speed;
void Attack() { }
}
static void Main(string[] args)
{
Monster monster = new Monster();
Type type = monster.GetType();
FieldInfo[] fields = type.GetFields(
BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance |
BindingFlags.Static);
foreach (FieldInfo field in fields)
{
string access = "protected";
if (field.IsPublic)
access = "public";
else if (field.IsPrivate)
access = "private";
Console.WriteLine($"{access} {field.FieldType.Name} {field.Name}");
}
}
}
}
🔎 한 줄 한 줄 분석
| 코드 | 설명 |
|---|
Type type = monster.GetType() | 몬스터 객체의 타입 정보를 Type으로 가져옴 |
GetFields(...) | 필드 정보들 가져옴 (접근 지정자, 타입 등 포함) |
BindingFlags | 어떤 필드들을 가져올지 조건 지정 |
field.IsPublic | public 여부 체크 |
field.FieldType.Name | 필드 자료형 이름 |
field.Name | 필드 이름 |
Console.WriteLine(...) | 필드 정보 출력 |
📌 BindingFlags 정리
| 플래그 | 의미 |
|---|
| Public | public 멤버만 |
| NonPublic | private/protected 멤버 포함 |
| Instance | 인스턴스 필드만 |
| Static | static 필드만 |
💎 출력 결과
public Int32 hp
protected Int32 attack
private Single speed
🌟 GetType()과 typeof 차이
| 구분 | 설명 | 예시 |
|---|
GetType() | 런타임에 객체 인스턴스의 타입을 알아냄 | monster.GetType() |
typeof | 컴파일 타임에 타입 정보를 가져옴 | typeof(Monster) |
📣 실전에서 Reflection은 언제 필요할까?
| 상황 | 설명 |
|---|
| 플러그인 시스템 | 외부 DLL에서 타입을 동적 로드 |
| 테스트 자동화 | 테스트 메서드 이름으로 동적 실행 |
| Unity Editor | 인스펙터에 private 멤버 표시 |
| ORM/Serialization | 객체를 JSON으로 변환할 때 필드 나열 |
🎀 Attribute와 Reflection
🎈 Attribute란?
- 런타임에 읽을 수 있는 메타데이터
- 주석처럼 보이지만, 컴파일 후에도 남아서 런타임에 읽을 수 있음
- 대표 예:
SerializedField
📐 Attribute 사용 예제
class Important : Attribute
{
string message;
public Important(string message) { this.message = message; }
}
class Monster
{
[Important("very important")]
public int hp;
protected int attack;
private float speed;
}
📐 Attribute 읽는 방법
FieldInfo field = type.GetField("hp");
var attributes = field.GetCustomAttributes();
📐 전체 코드 예제 (Attribute까지 포함)
using System;
using System.Reflection;
namespace CSharp
{
class Important : Attribute
{
string message;
public Important(string message) { this.message = message; }
}
class Monster
{
[Important("very important")]
public int hp;
protected int attack;
private float speed;
void Attack() { }
}
class Program
{
static void Main(string[] args)
{
Monster monster = new Monster();
Type type = monster.GetType();
FieldInfo[] fields = type.GetFields(
BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance |
BindingFlags.Static);
foreach (FieldInfo field in fields)
{
string access = field.IsPublic ? "public" :
field.IsPrivate ? "private" :
"protected";
var attributes = field.GetCustomAttributes();
Console.Write($"{access} {field.FieldType.Name} {field.Name}");
foreach (var attr in attributes)
{
if (attr is Important important)
{
Console.Write($" - Attribute: {important}");
}
}
Console.WriteLine();
}
}
}
}
📣 출력 예시
public Int32 hp - Attribute: Important
protected Int32 attack
private Single speed
📌 Attribute 정리
| 포인트 | 설명 |
|---|
| 선언 | class MyAttribute : Attribute |
| 부착 | [MyAttribute(...)] |
| 읽기 | GetCustomAttributes() |
🏁 정리 표
| 개념 | 설명 |
|---|
| Reflection | 런타임에 객체 정보를 읽고 조작 |
| GetType | 객체 타입 정보 조회 |
| typeof | 타입 직접 조회 (컴파일 타임) |
| GetFields | 필드 목록 조회 |
| Attribute | 런타임용 메타데이터 |
| Custom Attribute | 사용자 정의 메타데이터 |
🎁 실무 팁
- Reflection은 성능이 느립니다. 남발 금지!
- 자주 쓸 데이터는 캐싱 추천
- Unity에서는 커스텀 인스펙터 제작 시 필수
- JSON 직렬화/역직렬화 같은 라이브러리 내부도 Reflection 활용