산업 제조
산업용 사물 인터넷 | 산업자재 | 장비 유지 보수 및 수리 | 산업 프로그래밍 |
home  MfgRobots >> 산업 제조 >  >> Industrial programming >> C 언어

C# 리플렉션(Reflection) 마스터하기: 런타임 타입 발견과 동적 프로그래밍

리플렉션(Reflection) 객체는 런타임에 타입 정보를 얻는 데 사용됩니다. 실행 중인 프로그램의 메타데이터에 접근하는 클래스들은 System.Reflection 네임스페이스에 있습니다.

System.Reflection 네임스페이스는 애플리케이션 정보를 얻고, 런타임에 동적으로 타입, 값, 객체를 추가할 수 있는 클래스들을 포함합니다.

리플렉션의 응용

메타데이터 보기

앞 장에서 언급했듯 리플렉션으로 어트리뷰트 정보를 볼 수 있습니다.

System.Reflection.MemberInfo 객체를 초기화하여 클래스와 연관된 어트리뷰트 발견. 대상 클래스 객체 정의:

System.Reflection.MemberInfo info = typeof(MyClass);

기본 예제: 어트리뷰트 읽기

using System;

[AttributeUsage(AttributeTargets.All)]
public class HelpAttribute : System.Attribute
{
    public readonly string Url;
    public string Topic { get; set; }
    
    public HelpAttribute(string url) { Url = url; }
}

[HelpAttribute("Information on the class MyClass")]
class MyClass { }

namespace AttributeAppl
{
    class Program
    {
        static void Main(string[] args)
        {
            System.Reflection.MemberInfo info = typeof(MyClass);
            object[] attributes = info.GetCustomAttributes(true);
            
            for (int i = 0; i < attributes.Length; i++)
            {
                Console.WriteLine(attributes[i]);
            }
            Console.ReadKey();
        }
    }
}

출력: HelpAttribute

종합 예제: DeBugInfo 어트리뷰트 리플렉션으로 읽기

using System;
using System.Reflection;

namespace BugFixApplication
{
    // 커스텀 어트리뷰트 정의
    [AttributeUsage(
        AttributeTargets.Class | 
        AttributeTargets.Constructor | 
        AttributeTargets.Field | 
        AttributeTargets.Method | 
        AttributeTargets.Property,
        AllowMultiple = true
    )]
    public class DeBugInfo : System.Attribute
    {
        private int bugNo;
        private string developer;
        private string lastReview;
        public string Message { get; set; }
        
        public DeBugInfo(int bg, string dev, string d)
        {
            bugNo = bg; developer = dev; lastReview = d;
        }
        
        public int BugNo => bugNo;
        public string Developer => developer;
        public string LastReview => lastReview;
    }
    
    // 어트리뷰트 적용
    [DeBugInfo(45, "Zara Ali", "12/8/2012", Message = "Return type mismatch")]
    [DeBugInfo(49, "Nuha Ali", "10/10/2012", Message = "Unused variable")]
    class Rectangle
    {
        protected double length, width;
        
        public Rectangle(double l, double w) { length = l; width = w; }
        
        [DeBugInfo(55, "Zara Ali", "19/10/2012", Message = "Return type mismatch")]
        public double GetArea() { return length * width; }
        
        [DeBugInfo(56, "Zara Ali", "19/10/2012")]
        public void Display()
        {
            Console.WriteLine("Length: {0}", length);
            Console.WriteLine("Width: {0}", width);
            Console.WriteLine("Area: {0}", GetArea());
        }
    }
    
    class ExecuteRectangle
    {
        static void Main(string[] args)
        {
            Rectangle r = new Rectangle(4.5, 7.5);
            r.Display();
            
            Type type = typeof(Rectangle);
            
            // 클래스 레벨 어트리뷰트 읽기
            Console.WriteLine("=== 클래스 어트리뷰트 ===");
            foreach (object attr in type.GetCustomAttributes(false))
            {
                if (attr is DeBugInfo dbi)
                {
                    Console.WriteLine($"Bug No: {dbi.BugNo}");
                    Console.WriteLine($"Developer: {dbi.Developer}");
                    Console.WriteLine($"Last Reviewed: {dbi.LastReview}");
                    Console.WriteLine($"Remarks: {dbi.Message}");
                }
            }
            
            // 메서드 레벨 어트리뷰트 읽기
            Console.WriteLine("\n=== 메서드 어트리뷰트 ===");
            foreach (MethodInfo m in type.GetMethods())
            {
                foreach (Attribute a in m.GetCustomAttributes(true))
                {
                    if (a is DeBugInfo dbi)
                    {
                        Console.WriteLine($"Bug No: {dbi.BugNo}, Method: {m.Name}");
                        Console.WriteLine($"Developer: {dbi.Developer}");
                        Console.WriteLine($"Last Reviewed: {dbi.LastReview}");
                        Console.WriteLine($"Remarks: {dbi.Message}");
                    }
                }
            }
            
            Console.ReadLine();
        }
    }
}

출력:

Length: 4.5
Width: 7.5
Area: 33.75
=== 클래스 어트리뷰트 ===
Bug No: 49, Developer: Nuha Ali, Last Reviewed: 10/10/2012, Remarks: Unused variable
Bug No: 45, Developer: Zara Ali, Last Reviewed: 12/8/2012, Remarks: Return type mismatch
=== 메서드 어트리뷰트 ===
Bug No: 55, Method: GetArea, Developer: Zara Ali, Last Reviewed: 19/10/2012, Remarks: Return type mismatch
Bug No: 56, Method: Display, Developer: Zara Ali, Last Reviewed: 19/10/2012, Remarks: 

리플렉션 핵심 클래스

클래스용도
Type타입 정보의 루트. 타입 메타데이터 접근 시작점
Assembly어셈블리 로드, 타입 열거, 리소스 접근
MemberInfo멤버(필드, 메서드, 프로퍼티 등) 공통 기본 클래스
FieldInfo필드 정보 (이름, 타입, 값 읽기/쓰기)
MethodInfo메서드 정보 (호출, 매개변수, 반환 타입)
PropertyInfo프로퍼티 정보 (값 읽기/쓰기)
ConstructorInfo생성자 정보 (인스턴스 생성)
ParameterInfo매개변수 정보
EventInfo이벤트 정보
CustomAttributeData어트리뷰트 데이터 (로드하지 않고 검사 가능)

주요 리플렉션 작업

타입 정보 얻기

Type t = typeof(string);           // 컴파일 타임 타입에서
Type t2 = "hello".GetType();         // 인스턴스에서
Type t3 = Type.GetType("System.String"); // 문자열 이름으로

멤버 열거

Type t = typeof(MyClass);

// 모든 public 멤버
MemberInfo[] members = t.GetMembers();

// 특정 멤버 타입만
MethodInfo[] methods = t.GetMethods();
PropertyInfo[] props = t.GetProperties();
FieldInfo[] fields = t.GetFields();
ConstructorInfo[] ctors = t.GetConstructors();

// 바인딩 플래그로 비공개 포함
var allMethods = t.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);

동적 인스턴스 생성 및 메서드 호출

Type t = typeof(MyClass);

// 기본 생성자로 생성
object obj = Activator.CreateInstance(t);

// 매개변수 있는 생성자
object obj2 = Activator.CreateInstance(t, new object[] { "arg1", 123 });

// 메서드 호출
MethodInfo method = t.GetMethod("MyMethod");
object result = method.Invoke(obj, new object[] { "param1" });

// 프로퍼티 설정/가져오기
PropertyInfo prop = t.GetProperty("Name");
prop.SetValue(obj, "New Name");
string name = (string)prop.GetValue(obj);

제네릭 타입 다루기

Type openGeneric = typeof(List<>);
Type closedGeneric = openGeneric.MakeGenericType(typeof(int));  // List

object list = Activator.CreateInstance(closedGeneric);
MethodInfo add = closedGeneric.GetMethod("Add");
add.Invoke(list, new object[] { 42 });

성능 고려사항

// 캐싱 예제
private static readonly MethodInfo CachedMethod = typeof(MyClass).GetMethod("MyMethod");

public void FastInvoke(MyClass obj, string param)
{
    CachedMethod.Invoke(obj, new object[] { param });
}

// 델리게이트 변환으로 더 빠르게
private static readonly Func CachedDelegate = 
    (Func)Delegate.CreateDelegate(
        typeof(Func), 
        typeof(MyClass).GetMethod("MyMethod")
    );

public int FastestInvoke(MyClass obj, string param)
{
    return CachedDelegate(obj, param);
}
핵심: 리플렉션은 플러그인 아키텍처, 직렬화, ORM, 테스트 프레임워크, 의존성 주입 컨테이너 등 프레임워크/라이브러리 개발에 필수적입니다. 애플리케이션 코드에서는 신중히 사용하세요.

C 언어

  1. C# Hello World – 첫 C# 애플리케이션 만들기
  2. C# 키워드와 식별자 이해: 규칙, 목록, 모범 사례
  3. C# 변수와 기본 데이터 타입 완벽 가이드
  4. C# 연산자 – C# 연산자 종합 가이드
  5. C# 비트 연산자와 시프트 연산자 완전 정복: 종합 가이드
  6. C# 기초: 입출력(Essential Input/Output) 완벽 가이드
  7. C# 식, 문, 블록: 개념과 실전 예제로 완벽 이해
  8. C# 주석 마스터하기: 종류, 모범 사례, XML 문서화
  9. C# break 문: 사용법과 활용 시점 완벽 가이드
  10. C# continue 문: 루프 반복 건너뛰기 완벽 활용법