object vs dynamic vs var – 언제 뭘 써야 헷갈리지 않을까?
C# 코드 짜다 보면 아래 셋 중에 뭐 써야 할지 헷갈릴 때가 있다.
object something = ...;
dynamic something = ...;
var something = ...;
전부 '뭔가를 담을 수 있다'는 느낌인데…
똑같은 거 같으면서도 다르고, 다르다면서도 비슷하다.
"object는 옛날부터 있던 거고, dynamic은 늦게 생긴 거고, var은 타입 추론 아닌가?"
이 정도만 알고 있으면 실무에선 딱 사고 난다.
이번 챕터에선 이 셋을 진짜 제대로 구분해보자.
헷갈리는 개념, 예외 상황, 실무 기준 사용법까지 싹 정리해줄게.
문제 상황: 자동완성도 안 뜨고, 컴파일 에러도 없고?
dynamic x = "Hello";
Console.WriteLine(x.Length); // 가능
object y = "Hello";
Console.WriteLine(y.Length); // ❌ 컴파일 에러
어라? 둘 다 문자열인데 왜 object는 안 되고 dynamic은 되지?
핵심은 타입 해석 시점의 차이다.
- object: 컴파일 타임에 타입이 결정됨 (그래서 .Length 못 씀)
- dynamic: 런타임에 타입이 결정됨 (그래서 일단은 뭐든 호출 가능)
- var: 컴파일 타임에 명확한 타입으로 결정됨 (단, 선언할 때만!)
object – C#의 최상위 조상
모든 타입은 결국 object에서 파생된다.
그래서 어떤 타입이든 object 변수에 담을 수 있다.
object value = 123; // int
object text = "hello"; // string
object now = DateTime.Now; // DateTime
하지만 문제가 있다.
object로는 구체적인 멤버를 쓸 수 없다.
왜냐면 object 타입에 그런 게 없으니까.
object text = "hello";
Console.WriteLine(text.Length); // ❌ 컴파일 에러
Console.WriteLine(((string)text).Length); // ✅ 형변환 필요
object는 유연하지만, 구체적인 작업을 하려면 형변환이 필요하다.
dynamic – 일단 뭐든 해봐! (책임은 런타임에)
dynamic은 런타임까지 타입 검사를 미룬다.
컴파일러가 “나 몰라~ 일단 통과시킬게”라는 스타일.
dynamic x = "hello";
Console.WriteLine(x.Length); // ✅
dynamic y = 123;
Console.WriteLine(y.Length); // ❌ 컴파일은 되지만, 실행 중 예외
런타임에 잘못된 멤버를 호출하면 바로 예외가 터진다.
실무에서는? 외부 데이터 (예: JSON, COM, Reflection 등)를 다룰 때 잠깐 쓴다.
var – 타입 추론의 왕자님
var는 선언 시점에 타입을 추론해서 자동으로 결정해주는 키워드다.
한 번 결정된 타입은 고정된다.
var x = "hello"; // string
var y = 123; // int
var z = new List<string>(); // List
var는 타입을 감추는 게 아니라, 타입을 자동으로 결정해주는 것이다.
var a = null; // ❌ 에러: 타입 추론 불가
var b; // ❌ 에러: 반드시 초기화 필요
var x = "hello";
Console.WriteLine(x.Length); // ✅ 잘 동작
실무 예시: JSON, object, var, dynamic
string json = "{ \"Name\": \"철수\" }";
var obj = JsonSerializer.Deserialize<Dictionary<string, object>>(json);
Console.WriteLine(obj["Name"]); // object니까 형변환 필요
dynamic dyn = JsonSerializer.Deserialize<dynamic>(json);
Console.WriteLine(dyn.Name); // dynamic이니까 바로 접근 가능
object는 안전하지만 귀찮고,
dynamic은 편하지만 위험하다.
var는 명확한 타입을 추론할 수 있을 때 쓰면 깔끔하다.
언제 어떤 걸 써야 할까?
구분 | object | dynamic | var |
---|---|---|---|
타입 해석 시점 | 컴파일 타임 | 런타임 | 컴파일 타임 (추론) |
멤버 접근 | 형변환 필요 | 직접 접근 가능 | 타입에 따라 가능 |
타입 안정성 | 높음 | 낮음 | 높음 |
예외 가능성 | 컴파일 에러 | 런타임 예외 | 컴파일 에러 |
추천 상황 | 박싱된 값, 범용 컨테이너 | 외부 데이터(JSON 등) | 명확한 타입을 추론할 수 있을 때 |
마무리하며
셋 다 “뭔가 유연하게 값을 담는” 역할처럼 보이지만, 실제로는 전혀 다른 철학과 목적을 갖고 있다.
- "최대한 범용으로 받고 싶고, 타입은 나중에 처리한다" → object
- "외부 데이터니까 일단 접근하고, 예외는 감수하겠다" → dynamic
- "타입은 명확한데 코드 깔끔하게 쓰고 싶다" → var
실무에선 object와 dynamic을 무분별하게 남용하는 건 피하고, 가능하면 명확한 타입을 기반으로 코딩하는 습관을 들이자.
그게 유지보수와 안정성의 핵심이다.
'C#' 카테고리의 다른 글
async vs await – 비동기 코딩, 진짜 이해하고 쓰고 있나? (29) | 2025.06.07 |
---|---|
Nullable과 null 처리 전략 – null 때문에 또 터졌다고? (47) | 2025.06.06 |
값 타입 vs 참조 타입 – 구조체와 클래스, 뭐가 다른데? (22) | 2025.06.05 |
ref, out, in - C# 파라미터 키워드 제대로 구분하자 (18) | 2025.06.04 |
인터페이스 vs 추상 클래스, 진짜 차이가 뭔데? (26) | 2025.06.03 |