728x90
📘 Chapter 3.2: Reflection & Dynamic Type – 런타임 메타프로그래밍
✅ 이 챕터에서 배울 것
- 리플렉션(Reflection)이란?
- 어떤 상황에서 쓰는가 (실무 사례)
- Type, PropertyInfo, MethodInfo 사용법
- dynamic 키워드와 ExpandoObject
- 실전 시나리오 예제 (DTO ↔ Entity, 자동 매핑 등)
- 성능 이슈와 개선 전략
1️⃣ 리플렉션(Reflection)이란?
실행 중인 객체, 타입, 메서드, 속성 정보를 코드에서 직접 들여다보고 조작하는 기술
C#에서는 System.Reflection
네임스페이스를 통해 사용한다.
📦 간단 예제
Type type = typeof(string);
Console.WriteLine(type.FullName); // System.String
MethodInfo method = type.GetMethod("Contains");
Console.WriteLine(method.Name); // Contains
🧠 실무에서 어디 쓰이노?
- DI Container – 어떤 클래스를 만들고 어떤 인터페이스인지
- Moq, AutoFixture – 타입 자동 생성
- JsonSerializer – 속성들 순회
- EntityFramework – DTO ↔ Entity 매핑
- Swagger – 컨트롤러/파라미터 정보 추출
2️⃣ 실전 – 객체 속성 모두 출력하기
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
var person = new Person { Name = "장형", Age = 35 };
Type type = typeof(Person);
foreach (var prop in type.GetProperties())
{
Console.WriteLine($"{prop.Name}: {prop.GetValue(person)}");
}
✅ 결과:
Name: 장형
Age: 35
→ 객체의 모든 속성 정보를 동적으로 출력 가능
3️⃣ 동적으로 메서드 호출하기
public class Calculator
{
public int Add(int a, int b) => a + b;
}
var calc = new Calculator();
Type type = typeof(Calculator);
MethodInfo method = type.GetMethod("Add");
object result = method.Invoke(calc, new object[] { 3, 4 });
Console.WriteLine(result); // 7
✅ 컴파일 시점에 메서드 이름이 없어도
런타임에 찾아서 호출 가능! (플러그인 구조, 모듈 확장에 핵심)
4️⃣ dynamic – 타입 없이도 호출되는 마법
dynamic obj = "Hello";
Console.WriteLine(obj.Length); // 컴파일 시엔 체크 안 됨
✅ 특징:
- 타입을 런타임에 결정
- 컴파일러는 무시, 대신 런타임에 호출 성공 여부 판단
- 내부적으로 IDynamicMetaObjectProvider 기반 작동
🔧 ExpandoObject
완전 런타임 조작 가능한 객체 (속성 추가도 가능)
dynamic expando = new ExpandoObject();
expando.Name = "장형";
expando.SayHi = (Action)(() => Console.WriteLine("안녕~"));
Console.WriteLine(expando.Name);
expando.SayHi();
✅ 실무에서는 동적 바인딩, 스크립트 엔진, 데이터 표현 등에 자주 사용
5️⃣ 실무 예제 – DTO 자동 매핑기 만들기
public class UserDto
{
public string Name { get; set; }
public int Age { get; set; }
}
public class User
{
public string Name { get; set; }
public int Age { get; set; }
}
public static TTarget Map<TSource, TTarget>(TSource src)
where TTarget : new()
{
var target = new TTarget();
var sourceProps = typeof(TSource).GetProperties();
var targetProps = typeof(TTarget).GetProperties();
foreach (var sProp in sourceProps)
{
var tProp = targetProps.FirstOrDefault(p => p.Name == sProp.Name);
if (tProp != null && tProp.CanWrite)
{
tProp.SetValue(target, sProp.GetValue(src));
}
}
return target;
}
var dto = new UserDto { Name = "장형", Age = 35 };
var entity = Map<UserDto, User>(dto);
Console.WriteLine(entity.Name); // 장형
➡️ 실무에서 AutoMapper가 하는 일의 핵심 로직
6️⃣ 성능 이슈 & 대안
✅ 문제:
- 리플렉션은 런타임 탐색 → 속도 느림
- 코드가 복잡 → 예외 처리 어려움
- JIT 최적화 못 받음
✅ 대안:
방법 | 설명 |
---|---|
Expression Tree | 런타임에 코드 생성 후 컴파일 |
Source Generator | 컴파일 타임에 코드 생성 |
delegate 캐싱 | GetMethod 후 Delegate로 변환해서 재사용 |
var method = typeof(Calculator).GetMethod("Add");
var del = (Func<Calculator, int, int, int>)
Delegate.CreateDelegate(typeof(Func<Calculator, int, int, int>), method);
var result = del(new Calculator(), 3, 4); // 빠름!
✅ 정리 요약
항목 | 설명 |
---|---|
Reflection | 런타임에 타입/속성/메서드 조작 |
dynamic | 컴파일 타임 타입 무시, 런타임 결정 |
ExpandoObject | 속성도 런타임에 추가 가능한 객체 |
실무 활용 | ORM, DI, 시리얼라이저, Mock, Swagger |
성능 대안 | Expression, Source Generator, Delegate 캐싱 |
📢 다음 챕터 예고 🎓
다음 챕터 | 주제 |
---|---|
Chapter 3.3 | Expression Tree로 컴파일 타임 코드 생성 |
728x90
'C#' 카테고리의 다른 글
C# 기초부터 고급까지 Chapter 3.4. 고급 LINQ 커스터마이징 & 쿼리 최적화 (2) | 2025.05.06 |
---|---|
C# 기초부터 고급까지 Chapter 3.3. Expression Tree로 컴파일 타임 코드 생성 (8) | 2025.05.05 |
C# 기초부터 고급까지 Chapter 3.1. Span , Memory , Unsafe – 퍼포먼스 챙기는 C# 코드 (0) | 2025.05.04 |
C# 기초부터 고급까지 Chapter 2.10. 프로젝트 구조 패턴 – Layered vs Clean Architecture 소개 (0) | 2025.05.04 |
C# 기초부터 고급까지 Chapter 2.9. 인터페이스 활용 – 다형성 실전 예제 (2) | 2025.05.03 |