dynamic vs Reflection, 그리고 var / object와의 관계

황현중·2025년 12월 9일

1. dynamic vs reflection – 코드 스타일 / 사용성

1) dynamic

  • 마치 정적 타입인 것처럼 점(.) 찍고 바로 사용할 수 있다.
  • 문법이 깔끔하고 짧다.
  • 내부적으로는 런타임 바인딩(reflection + 캐시 등)을 사용해서 어떤 멤버를 호출할지 결정한다.

2) reflection

  • Type, MethodInfo, PropertyInfo 같은 타입을 직접 다룬다.
  • 코드가 길어지고, 멤버 이름을 문자열로 다루기 때문에 오타에 취약하다.
  • 그 대신 더 저수준 제어가 가능하다. (멤버 나열, 특정 조건으로 필터링 등)

2. dynamic vs reflection – 기능 / 유연성 측면

1) dynamic이 어울리는 경우

  • “이 멤버가 있다는 걸 안다”는 전제 하에, 그냥 편하게 호출하고 싶을 때
  • JSON / COM / 스크립트 객체처럼, “형태는 대충 아는데 타입 선언이 귀찮은” 경우

예:

dynamic json = JsonConvert.DeserializeObject(jsonText);

Console.WriteLine(json.name);
Console.WriteLine(json.address.city);

DTO를 정식으로 만들기 전, 프로토타입/테스트 단계에서 빠르게 다뤄볼 때도 많이 사용한다.

2) reflection이 어울리는 경우

  • 멤버 이름을 미리 모르는 상태에서, 런타임에 타입 구조를 탐색해야 할 때
  • 대표적인 사용 예:
    • DTO 자동 매핑 (프로퍼티 이름대로 값을 복사)
    • 객체의 모든 속성을 읽어서 로그 출력
    • 특정 Attribute가 붙은 멤버만 골라서 처리
  • dynamic보다 더 로우레벨 도구라서, “멤버가 무엇이 있는지”를 발견하는 작업에 적합하다.

예:

Type type = obj.GetType();
foreach (var prop in type.GetProperties())
{
    var value = prop.GetValue(obj);
    Console.WriteLine($"{prop.Name} = {value}");
}

3. 성능 관점

  • 정적 호출보다 둘 다 느리다는 점은 공통이다.
  • dynamic은 내부적으로 한 번 바인딩한 결과를 캐시하는 등 최적화가 들어가 있지만, 여전히 정적 호출보다는 비싸다.
  • reflection은 개발자가 잘못 쓰면 훨씬 비싸질 수 있다.
    • 예: 루프 안에서 매번 GetMethod, GetProperty 호출
  • 실무에서는 보통:
    • 핵심 로직 / 성능이 중요한 반복문 안에서는 둘 다 피하고,
    • 초기화, 설정, 매핑, 플러그인 로딩 같은 “바깥쪽”에서만 사용하는 경우가 많다.

4. 에러가 언제 터지느냐 (에러 시점)

1) dynamic

  • 멤버가 없거나 시그니처가 맞지 않으면 → 런타임에 RuntimeBinderException 발생
  • 컴파일은 일단 다 통과한다.
dynamic d = "Hello";
d.NonExistMethod(); // 컴파일 OK, 실행 시 RuntimeBinderException

2) reflection

  • 멤버를 찾을 때 null 여부를 체크해서, 예외를 직접 제어할 수 있다.
  • 단, 잘못된 방식으로 Invoke하면 여전히 런타임 예외가 발생한다.
var mi = obj.GetType().GetMethod("Run");
if (mi != null)
{
    mi.Invoke(obj, null); // 시그니처가 맞지 않으면 여기서 예외
}
else
{
    Console.WriteLine("Run 메서드가 없습니다.");
}

5. 함께 정리: dynamic / object / var

dynamic과 reflection을 이해할 때 자주 같이 언급되는 키워드가 var, object라서, 간단하게 비교해 두면 기억하기 좋다.

  • var
    • 그냥 컴파일 타임 타입 추론이다.
    • 한 번 타입이 결정되면 일반 변수와 똑같이 타입이 고정된다.
    • 타입 안전하고, 제일 많이 쓰는 기본 문법.
  • object
    • 모든 타입의 최상위 타입.
    • 형변환 + 박싱/언박싱이 필요할 수 있다.
    • 제네릭이 없던 시절 컬렉션에서 많이 쓰였던 방식 (예: ArrayList).
  • dynamic
    • 타입 체크를 런타임으로 미룬다.
    • 문법은 편하지만, 타입 안정성과 성능을 조금 희생한다.
    • JSON/COM/스크립트/실험용 코드 등에 적당하다.

0개의 댓글