dynamic 타입 정의 및 특징
dynamic 키워드는 컴파일 타임에 타입 검사를 건너뛰고, 런타임에 타입 검사를 수행하도록 하는 기능이다. 이는 정적 타입 언어인 C# 언어에 동적 언어의 유연성을 도입하기 위해 사용한다.
| 구분 | 설명 |
|---|---|
| 정의 | 컴파일러가 타입을 알 수 없도록 속이는 방법으로, 변수 선언 시 사용하여 내부적으로 object 타입으로 처리한다. |
| 타입 검사 시점 | 런타임에 결정된다. 컴파일 타임에는 dynamic 변수를 통해 호출되는 메소드나 속성이 존재하는지 검사하지 않는다. |
| 오류 발생 시점 | 잘못된 멤버를 호출하거나 타입이 일치하지 않을 경우, 컴파일 오류가 아닌 런타임 오류가 발생한다. |
| 핵심 기술 | DLR(Dynamic Language Runtime) |
다이나믹에 대한 예제 코드는 다음과 같다.
// dynamic 형식 사용 예제
dynamic x = 10; // x는 현재 int 타입의 10
x = "Hello, world"; // 런타임에 string 타입으로 변경 가능
Console.WriteLine(x.Length); // 컴파일러는 Length가 있는지 모르지만, string에는 있으므로 런타임에 성공
// x.NonExistentMethod(); // 컴파일 오류는 없으나, 실행 시 런타임 오류 발생
덕 타이핑
덕 타이핑(Duck Typing)은 객체가 어떤 클래스에 속하는지 보다, 객체가 어떤 메소드나 속성을 가지고 있는가에 초점을 맞춰 타입을 결정하는 동적 언어의 특성으로, C# 언어에서 dynamic 키워드로 구현할 수 있다.
- dynamic 키워드와 덕 타이핑: dynamic 변수를 통해 특정 메소드를 호출할 때, 컴파일러는 오류를 보고하지 않는다. 실제 객체가 해당 메소드를 런타임에 가지고 있다면 호출이 성공하며, 이는 덕 타이핑의 작동 방식과 일치한다.
// 서로 다른 타입이지만, 공통적으로 PrintName()을 호출할 수 있다고 가정
dynamic obj = GetDynamicObject(); // 런타임에 Person 또는 Company 객체가 될 수 있음
// 컴파일러는 오류를 모르고 넘어간다. 런타임에 PrintName()이 있는지 확인
obj.PrintName();
상호 운용성
dynamic 키워드의 주요 목적은 동적 타입 시스템이나 컴포넌트와의 상호 운용성을 높이는 것이다.
- COM(Component Object Model)과의 상호 운용성: COM은 Office 응용 프로그램 제어에 주로 사용된다. COM 객체는 정적 타입 정보가 부족하거나 타입 정보를 런타임에 노출시키는 경우가 많다. 이때 dynamic 키워드를 사용하면 COM 객체를 마치 .NET 객체처럼 직관적으로 호출할 수 있다. dynamic 키워드가 런타임에 COM 객체의 실제 타입을 분석하고 호출을 바인딩한다.
COM과 dynamic 관련 예제 코드는 다음과 같다.
// 예: 엑셀 COM 객체를 다룰 때
// Excel.Application excelApp = new Excel.Application();
// dynamic workSheet = excelApp.ActiveWorkbook.Sheets[1];
// workSheet.Cells[1, 1].Value2 = "Hello Dynamic"; // COM 호출이 간단해짐
-
동적 언어와의 상호 운용성: DLR 위에 구축된 동적 언어와 C# 코드 같의 데이터 및 메소드 호출 상호 작용을 간소화하는데 사용된다. 동적 언어에서 생성된 객체를 C# 코드에서 dynamic으로 받으면, 해당 객체의 동적 멤버를 정적 타입 검사 없이 호출할 수 있다.
-
.NET 런타임 상호 운용성(리플렉션 대체): 과거에 런타임에 타입 정보를 이용해 메소드를 호출하려면 복잡하고 성능이 느린 리플렉션을 사용해야 했지만, dynamic 객체는 DLR을 통해 캐싱과 최적화가 이루어지므로 리플렉션과 유사하게 작동하지만 성능이 좋다. 또한 문법적으로 리플렉션보다 간단하고 직관적이다.
dynamic 키워드 사용 시 유의사항
키워드 사용 시 유의사항은 다음과 같다.
-
타입 오류 지연: 타입 오류가 컴파일 시점이 아닌 런타임에 발생하므로, 디버깅이 더 어려워지고 예상치 못한 오류로 애플리케이션이 종료될 수 있다.
-
성능 오버헤드: 아무리 DLR이 최적화되어도 정적 바인딩보다 동적 바인딩이 느리므로, 성능에 민감한 루프에서는 사용을 피해야 한다.
-
코드 가독성 저하: 타입을 명확히 알 수 없어 코드를 읽고 이해하기 어려워질 수 있습니다. 반드시 상호 운용성 등 명확한 이유가 있을 때만 제한적으로 사용해야 합니다.