프로그래밍/C#

C# 리플렉션: 동적 프로그래밍의 강력한 도구

shimdh 2025. 9. 6. 10:13
728x90

C#의 리플렉션은 런타임에 타입의 메타데이터를 검사할 수 있는 강력한 기능입니다. 이는 컴파일 시점에 클래스의 구조를 알지 못하더라도 속성, 메서드, 이벤트 및 기타 멤버를 조사할 수 있음을 의미합니다. 리플렉션을 이해하는 것은 플러그인 아키텍처나 사용자 정의 타입과 상호작용해야 하는 프레임워크와 같은 동적 동작이 필요한 시나리오에서 매우 중요합니다.

리플렉션의 주요 개념

메타데이터

  • 메타데이터는 프로그램의 타입에 대한 데이터를 설명합니다. 클래스 이름, 메서드 시그니처, 속성 타입 및 속성 등의 정보를 포함합니다.
  • 코드를 컴파일할 때, 이 메타데이터는 컴파일러가 생성한 어셈블리(DLL 또는 EXE 파일)에 저장됩니다.

타입

  • C#에서는 모든 것이 System.Object에서 파생된 객체입니다. 리플렉션을 통해 이러한 객체를 동적으로 다룰 수 있습니다.
  • 리플렉션을 사용하여 타입의 인스턴스를 생성하고, 메서드를 호출하며, 필드나 속성에 직접 접근할 수 있습니다.

어셈블리

  • 어셈블리는 배포 및 버전 관리를 위해 사용되는 컴파일된 코드 라이브러리입니다.
  • 리플렉션을 통해 Assembly 클래스가 제공하는 메서드를 사용하여 어셈블리를 동적으로 로드할 수 있습니다.
728x90

실용적인 예제

1. 타입 검사

리플렉션을 사용하여 타입에 대한 정보를 얻을 수 있습니다:

using System;
using System.Reflection;

public class SampleClass
{
    public int MyProperty { get; set; }

    public void MyMethod()
    {
        Console.WriteLine("Hello from MyMethod!");
    }
}

class Program
{
    static void Main(string[] args)
    {
        Type sampleType = typeof(SampleClass);

        // 속성 가져오기
        PropertyInfo[] properties = sampleType.GetProperties();
        foreach (var prop in properties)
        {
            Console.WriteLine($"Property: {prop.Name}, Type: {prop.PropertyType}");
        }

        // 메서드 가져오기
        MethodInfo[] methods = sampleType.GetMethods();
        foreach (var method in methods)
        {
            Console.WriteLine($"Method: {method.Name}");
        }
    }
}

이 예제에서는 SampleClass라는 간단한 클래스를 정의하고, 하나의 속성과 하나의 메서드를 포함합니다. 리플렉션(typeof(SampleClass))을 사용하여 런타임에 속성과 메서드를 동적으로 검색합니다.

2. 동적 인스턴스 생성

리플렉션은 타입을 사전에 알지 못하더라도 클래스의 인스턴스를 생성할 수 있게 해줍니다:

public class AnotherSampleClass
{
    public string Message { get; set; }

    public AnotherSampleClass(string message)
    {
        Message = message;
    }

    public void ShowMessage()
    {
       Console.WriteLine(Message);
    }
}

class Program
{
     static void Main(string[] args)
     {
          Type anotherSampleType = typeof(AnotherSampleClass);
          object instance = Activator.CreateInstance(anotherSampleType,
              new object[] { "Hello from AnotherSample!" });

          MethodInfo showMessageMethod = anotherSampleType.GetMethod("ShowMessage");
          showMessageMethod.Invoke(instance,null);  // 생성된 인스턴스에서 ShowMessage 메서드 호출.
     }
}

이 예제에서는 AnotherSampleClass의 인스턴스를 Activator.CreateInstance를 사용하여 동적으로 생성합니다. 그런 다음 리플렉션을 사용하여 메서드를 호출합니다.

3. 속성과 함께 작업하기

속성은 클래스나 멤버에 대한 추가 메타데이터를 제공하며, 리플렉션을 통해 접근할 수 있습니다:

[AttributeUsage(AttributeTargets.Class)]
public class CustomAttribute : Attribute 
{
      public string Description { get; }

      public CustomAttribute(string description) => Description = description;
}

[Custom("This is a custom attribute.")]
public class YetAnotherExample {}

class Program 
{
     static void Main(string[] args) 
     {
         Type yetAnotherExampleType = typeof(YetAnotherExample);
         var attributes = yetAnotherExampleType.GetCustomAttributes(false);

         foreach (var attr in attributes) 
         {
             if(attr is CustomAttribute customAttr) 
             {
                 Console.WriteLine($"Description: {customAttr.Description}");
             }
         }  
     }
}

여기서 CustomAttribute라는 사용자 정의 속성을 정의합니다. 이 속성은 YetAnotherExample 클래스에 적용됩니다. 리플렉션(GetCustomAttributes())을 사용하여 런타임에 설명을 검색하고 표시합니다.

결론

리플렉션은 C#에서 타입을 다룰 때 상당한 유연성을 제공합니다. 동적 타입 생성 및 실행 중 멤버 세부 정보 검사와 같은 많은 가능성을 열어주지만, 직접 코딩 방식에 비해 잠재적인 성능 영향을 고려하여 신중하게 사용해야 합니다. 리플렉션의 작동 방식을 이해하면 다양한 시나리오를 효과적으로 처리할 수 있는 더 적응력 있는 코드를 작성할 수 있습니다!

728x90