C#의 리플렉션과 동적 코드 생성은 개발자에게 런타임 시 객체와 상호작용할 수 있는 강력한 도구를 제공합니다. 이 블로그에서는 리플렉션의 주요 개념과 동적 코드 생성의 실용적인 예제를 통해 이러한 기능이 어떻게 활용될 수 있는지 살펴보겠습니다.
리플렉션의 이해
리플렉션은 런타임에 객체의 타입을 검사하고 조작할 수 있는 기능을 제공합니다. 이를 통해 어셈블리, 모듈, 타입, 메서드, 속성, 필드, 이벤트에 대한 정보를 얻을 수 있습니다. 특히 동적 동작이 필요한 애플리케이션이나 타입 정보가 유연해야 하는 프레임워크 개발에 유용합니다.
리플렉션의 주요 기능
- 타입 검사: 애플리케이션 내의 클래스나 인터페이스의 메타데이터를 검사할 수 있습니다.
- 동적 호출: 컴파일 시점에 알지 못하는 메서드를 동적으로 호출할 수 있습니다.
- 속성 읽기: 클래스나 멤버에 적용된 사용자 정의 속성을 읽어 추가적인 동작을 가능하게 합니다.
리플렉션의 실용적인 예제
다음은 리플렉션을 사용하여 SampleClass의 메서드를 검사하고 동적으로 호출하는 예제입니다:
using System;
using System.Reflection;
public class SampleClass
{
[Obsolete("This method is obsolete.")]
public void OldMethod()
{
Console.WriteLine("Old Method");
}
public void NewMethod()
{
Console.WriteLine("New Method");
}
}
class Program
{
static void Main(string[] args)
{
Type type = typeof(SampleClass);
// SampleClass의 모든 메서드 가져오기
MethodInfo[] methods = type.GetMethods();
foreach (var method in methods)
{
// 메서드에 Obsolete 속성이 있는지 확인
if (method.GetCustomAttribute<ObsoleteAttribute>() != null)
{
Console.WriteLine($"{method.Name} is marked as obsolete.");
}
else
{
Console.WriteLine(method.Name);
}
}
// 메서드 동적 호출
var instance = Activator.CreateInstance(type);
var newMethod = type.GetMethod("NewMethod");
newMethod.Invoke(instance, null); // 출력: New Method
}
}
이 예제에서는 SampleClass의 메서드를 검사하고, Obsolete 속성이 있는지 확인한 후, NewMethod를 동적으로 호출합니다.
동적 코드 생성
동적 코드 생성은 런타임에 중간 언어(IL) 코드를 생성하는 것을 의미합니다. 이를 통해 개발자는 컴파일 타임에 미리 정의된 구조 없이 새로운 타입을 생성하거나 기존 타입을 수정할 수 있습니다.
동적 코드 생성의 주요 개념
- 동적 어셈블리: 실행 중에 하나 이상의 동적 타입을 포함하는 어셈블리를 생성합니다.
- 동적 타입: 실행 중에 클래스/인터페이스/메서드/속성을 동적으로 정의합니다.
- 성능 이점: IL이 직접 생성되므로 소스 코드에서 해석되는 것보다 성능이 향상되는 경우가 많습니다.
동적 코드 생성의 실용적인 예제
다음은 단일 메서드를 가진 간단한 클래스를 동적으로 생성하는 방법입니다:
using System;
using System.Reflection;
using System.Reflection.Emit;
class Program
{
static void Main(string[] args)
{
// 동적 어셈블리 및 모듈 정의
AssemblyName assemblyName = new AssemblyName("DynamicAssembly");
AssemblyBuilder assemblyBuilder =
AssemblyBuilder.DefineDynamicAssembly(assemblyName,
AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder =
assemblyBuilder.DefineDynamicModule("MainModule");
// "MyDynamicType"이라는 공개 클래스 정의
TypeBuilder typeBuilder =
moduleBuilder.DefineType("MyDynamicType", TypeAttributes.Public);
// "SayHello"라는 메서드 정의, 반환값 없음
MethodBuilder methodBuilder =
typeBuilder.DefineMethod(
"SayHello",
MethodAttributes.Public,
null,
null);
ILGenerator ilGenerator = methodBuilder.GetILGenerator();
// SayHello의 IL 코드 생성 - "Hello World!" 출력
ilGenerator.EmitWriteLine("Hello World!");
ilGenerator.Emit(OpCodes.Ret);
Type myType = typeBuilder.CreateType();
// 인스턴스 생성 및 SayHello 호출
object obj = Activator.CreateInstance(myType);
myType.InvokeMember(
"SayHello",
BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance,
null,
obj,
null); // 출력: Hello World!
}
}
이 예제에서는 "DynamicAssembly"라는 동적 어셈블리와 "MainModule"이라는 모듈이 생성되고, 그 모듈 내에 "MyDynamicType"이라는 새로운 클래스가 정의됩니다. "SayHello"라는 공개 메서드는 호출 시 "Hello World!"를 출력하는 IL 명령을 생성합니다.
결론
리플렉션과 동적 코드 생성은 C#에서 객체를 보다 일반적으로 런타임에 다룰 수 있게 해주는 고급 기능입니다. 이러한 기능은 플러그인 아키텍처와 같은 시나리오에서 컴포넌트를 사용자 입력이나 구성 파일에 따라 동적으로 로드할 수 있게 하여 애플리케이션을 다시 컴파일하지 않고도 유연하게 동작할 수 있게 합니다. 이러한 개념을 이해하면 런타임 조건에 따라 동작을 조정할 수 있는 강력한 애플리케이션을 만드는 많은 가능성을 열어줍니다!
'프로그래밍 > C#' 카테고리의 다른 글
| C#에서의 동적 프로그래밍: ExpandoObject와 DynamicObject의 활용 (0) | 2025.09.15 |
|---|---|
| C#에서의 동적 프로그래밍: 유연성과 적응력의 새로운 지평 (0) | 2025.09.15 |
| C# 리플렉션: 런타임 객체 조작의 강력한 도구 (0) | 2025.09.15 |
| 비동기 프로그래밍의 핵심: Task-Based Asynchronous Pattern(TAP) 이해하기 (0) | 2025.09.14 |
| 비동기 프로그래밍의 힘: C#에서의 Async와 Await 활용 (0) | 2025.09.14 |