
지금까지 우리는 리플렉션의 핵심인 Type클래스를 탐험하며
클래스의 설계도(메소드, 속성 등)를 엿보는 방법을 알아봤습니다.
설계도를 손에 넣었으니, 이제 직접 무언가를 만들어 볼 차례겠죠?
이번 포스팅에서는 런타임에 클래스 이름만으로 동적으로 객체를 생성하고,
그 객체의 메소드까지 호출하는 방법에 대해 깊이 파고들어 보겠습니다!
"리플렉션으로 객체를 어떻게 만들지?"라는 질문에 가장 먼저 등장하는 해결사가 있습니다.
바로 System.Activator클래스입니다. 이름부터가 '활성자'라는 뜻으로,
객체 생성을 전문적으로 담당하는 친구라고 생각하면 쉽습니다.
Activator클래스의 가장 대표적인 메소드는 CreateInstance()입니다.
이 메소드는 여러 가지 버전(오버로드)이 있지만, 가장 핵심적인 사용법은 다음과 같습니다.
Activator.CreateInstance(Type type)Activator.CreateInstance(Type type, object[] args)args배열에 생성자에 전달할 인자들을 순서대로 넣어주면 됩니다.이 Activator만 있으면, 우리는 컴파일 시점에는 어떤 클래스인지 몰라도
런타임에 Type정보만으로 해당 클래스의 인스턴스를 만들어낼 수 있습니다.
ReportGenerator라는 간단한 클래스를 예제로
직접 객체를 생성하고 메소드를 호출하는 전체 과정을 살펴보겠습니다.
[코드]
using System;
using System.Reflection;
// 과정1: ReportGenerator 클래스 준비
// 동적으로 생성해 볼 클래스
public class ReportGenerator
{
public string Title { get; private set; }
public string Format { get; private set; }
// 1. 매개변수 없는 생성자
public ReportGenerator()
{
Title = "기본 보고서";
Format = "TXT";
}
// 2. 매개변수 있는 생성자
public ReportGenerator(string title, string format)
{
Title = title;
Format = format;
}
public void Generate()
{
Console.WriteLine($"'{Title}' 보고서를 '{Format}' 형식으로 생성합니다.");
LogStatus("생성 완료");
}
private void LogStatus(string status)
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] 상태: {status}");
}
}
class Program
{
static void Main()
{
// 과정2: 리플렉션을 사용하여 객체 생성 및 메소드 호출
// 1. Type 정보 가져오기
Type reportType = typeof(ReportGenerator);
Console.WriteLine($"'{reportType.Name}' 타입의 정보를 찾았습니다.\n");
// 2. 매개변수 없는 생성자로 객체 생성
Console.WriteLine(">> 기본 생성자로 객체 생성 시도...");
object basicReportInstance = Activator.CreateInstance(reportType);
// 생성된 객체의 메소드 호출
MethodInfo generateMethod = reportType.GetMethod("Generate");
generateMethod.Invoke(basicReportInstance, null);
Console.WriteLine();
// 3. 매개변수 있는 생성자로 객체 생성
Console.WriteLine(">> 매개변수가 있는 생성자로 객체 생성 시도...");
object[] ctorArgs = { "월간 판매 보고서", "PDF" };
object customReportInstance = Activator.CreateInstance(reportType, ctorArgs);
// 속성 값도 한번 읽어볼까요?
PropertyInfo titleProperty = reportType.GetProperty("Title");
string title = (string)titleProperty.GetValue(customReportInstance);
Console.WriteLine($"생성된 객체의 제목: {title}");
// 다시 메소드 호출
generateMethod.Invoke(customReportInstance, null);
Console.WriteLine();
// 4. (심화) Private 메소드 호출하기
Console.WriteLine(">> Private 메소드 호출 시도...");
MethodInfo logMethod =
reportType.GetMethod(
"LogStatus", // 'LogStatus'라는 메소드 이름
BindingFlags.NonPublic | // 비공개(private) 메소드
BindingFlags.Instance); // 인스턴스 메소드
logMethod.Invoke(customReportInstance, new object[] { "수동 상태 기록" });
}
}
[실행 결과]
'ReportGenerator' 타입의 정보를 찾았습니다.
>> 기본 생성자로 객체 생성 시도...
'기본 보고서' 보고서를 'TXT' 형식으로 생성합니다.
[10:45:55] 상태: 생성 완료
>> 매개변수가 있는 생성자로 객체 생성 시도...
생성된 객체의 제목: 월간 판매 보고서
'월간 판매 보고서' 보고서를 'PDF' 형식으로 생성합니다.
[10:45:55] 상태: 생성 완료
>> Private 메소드 호출 시도...
[10:45:55] 상태: 수동 상태 기록
코드에서 볼 수 있듯이, Activator.CreateInstance로 객체를 만든 뒤,
GetMethod, GetProperty등으로 원하는 멤버 정보를 가져오고,
Invoke나 GetValue같은 메소드를 이용해 실제 동작을 실행하거나 값을 읽어올 수 있습니다.
여기서 Invoke 메소드란?
MethodInfo객체에서 사용하는Invoke메소드는 '실행하다'라는 뜻입니다.
리플렉션으로 찾아낸 메소드를 실제로 동작시키는 역할을 하죠.
첫 번째 인자로는 어떤 인스턴스에서 이 메소드를 실행할지 알려주고,
두 번째 인자로는 해당 메소드에 전달할 값(없으면null)을 넘겨줍니다.
이번 글에서 리플렉션의 동적 객체 생성에 대해 알아보았습니다.
Activator클래스를 이용해 런타임에 객체를 만들고, MethodInfo의
Invoke메소드를 통해 동적으로 메소드를 호출하는 강력한 기능을 직접 확인했죠.
이러한 기능은 플러그인 시스템, 의존성 주입(DI) 프레임워크 등
고수준의 유연한 아키텍처를 설계하는 데 핵심적인 역할을 합니다.