C# Reflection: 런타임에서 클래스의 메소드명과 변수명을 조사

C#에서 리플렉션(Reflection) 은 런타임에서 클래스, 생성자, 메서드 및 필드를 조사하고 조작할 수 있게 해줍니다.
리플렉션은 메타데이터, CIL 코드, 런타임에 바인딩 및 자체 생성 코드를 검사하기 위한 런타임 형식 검색 프로세스입니다.

예를 들어, 우리는 다음과 같이 Student라는 클래스를 정의했습니다.

class Student
{
    // 필드 
    public int age;
    // 메서드 
    public void score()
    {
        // .. 일부 코드
    }
}

위의 Student 클래스는 필드와 메서드로 구성되어 있습니다. Reflection의 도움을 받아 우리는 런타임에서 이 정보를 조사할 수 있습니다.

아래에서 Reflection에 대해 자세히 알아보겠습니다.

C# Reflection이란?

C#에서는 코드가 성공적으로 컴파일 된 후에 컴파일러에 의해 자동으로 생성되는 Assembly라는 블록이 있습니다. 이는 중간 언어 및 메타데이터 두 부분으로 구성됩니다.

우리가 C# 코드를 작성할 때, 이것은 직접 기계 수준 언어로 컴파일되지 않습니다. 먼저 중간 언어로 컴파일되고 이를 어셈블리로 패키징합니다.

마찬가지로 메타데이터는 클래스, 메서드, 생성자 등과 같은 유형에 대한 정보를 포함합니다. 예를 들어, Student 클래스는 일부 메서드 및 필드를 포함합니다. Student 클래스에 대한 이 모든 정보는 메타데이터 형식으로 제공됩니다.

Reflection은 단순히 해당 메타데이터를 가져와 내부 정보를 검사하는 것입니다.

C# Type 클래스

메타데이터에 액세스하는 주요 방법은 Type 클래스를 사용하는 것입니다. 이 클래스는 유형 선언에 대한 정보를 얻을 수 있는 메서드와 속성을 제공합니다. 예를 들어,

using System;
using System.Reflection;

public class Program
{
    public static void Main()
    {
        String studentName = "하로";

        // studentName의 현재 유형을 가져옴
        Type studentNameType = studentName.GetType();

        Console.WriteLine("유형은: " + studentNameType);
    }
}
C# Reflection: 런타임에서 클래스의 메소드명과 변수명을 조사
그림1. 출력

위 예제에서는 String 클래스 변수 studentName을 정의했습니다. 다음 코드에 주목하세요.

// studentName의 현재 유형을 가져옴
Type studentNameType = studentName.GetType();

GetType() 메서드는 현재 데이터의 Type을 반환합니다. 여기서는 GetType()을 studentName과 함께 사용하고 이를 Type 변수 studentNameType에 할당했습니다.

GetType() 메서드는 studentName의 현재 유형인 System.String을 반환합니다.

Assembly 가져오기를 위한 C# Reflection

Type 클래스는 Assembly를 생성하는 Assembly라는 속성을 제공합니다. 예를 들어,

using System;
using System.Reflection;

class Program
{
    static void Main()
    {
        // Program 클래스의 typeof 가져오고 이를 Type 변수 t에 로드
        Type t = typeof(Program);

        // Assembly 속성을 사용하여 변수 t의 Assembly 가져오기
        Console.WriteLine(t.Assembly);
    }
}
C# Reflection: 런타임에서 클래스의 메소드명과 변수명을 조사
그림2. 출력

위 예제에서는 다음 코드에 주목하세요.

// Program의 형식 가져오기 및 Type 변수 t에 로드
Type t = typeof(Program);

여기서 typeof 연산자를 사용하여 Program 클래스의 형식을 가져오고 Type 변수 t에 할당했습니다.

그런 다음 t를 사용하여 Program 클래스의 어셈블리를 반환하는 Assembly 속성을 사용했습니다.

C# Reflection 을통한 Enumerable 조사

Type 클래스의 속성을 사용하여 Enumerable 형식에 대한 정보를 얻을 수 있습니다. 예를 들어,

using System;
using System.Reflection;

class Program
{
    static void Main()
    {
        // Enumerable의 typeof 가져오고 이를 Type 변수 t에 로드
        Type t = typeof(Enumerable);

        // Type 클래스 속성을 사용하여 Enumerable 형식에 대한 정보 출력
        Console.WriteLine("이름 : {0}", t.Name);
        Console.WriteLine("네임스페이스 : {0}", t.Namespace);
        Console.WriteLine("베이스 유형 : {0}", t.BaseType);
    }
}
C# Reflection: 런타임에서 클래스의 메소드명과 변수명을 조사
그림3. 출력

위 예제에서는 Type 클래스의 속성을 Enumerable 형식과 함께 사용한 것에 주목하세요.

  • t.Name – 형식의 이름을 가져옵니다.
  • t.Namespace – 형식의 네임스페이스를 가져옵니다.
  • t.BaseType – 기본 또는 부모 형식을 가져옵니다.

C# Reflection 의 String 조사

Type 클래스의 속성을 사용하여 String 형식에 대한 정보도 얻을 수 있습니다. 예를 들어,

using System;
using System.Reflection;

class Program
{
    static void Main()
    {
        // typeof String의 정보를  가져오고 이를 Type 변수 t에 로드
        Type t = typeof(String);

        // Type 클래스 속성을 사용하여 String 형식에 대한 정보 출력
        Console.WriteLine("이름 : {0}", t.Name);
        Console.WriteLine("네임스페이스 : {0}", t.Namespace);
        Console.WriteLine("베이스 유형 : {0}", t.BaseType);
    }
}
C# Reflection: 런타임에서 클래스의 메소드명과 변수명을 조사
그림4. 출력

C#에서 Reflection을 사용하여 클래스, 대리자, 배열 등의 다른 유형에 대한 정보를 얻을 수 있습니다.

속성 및 필드 조작하기

PropertyInfo propertyInfo = myType.GetProperty("MyProperty");
propertyInfo.SetValue(myObject, 42);
int value = (int)propertyInfo.GetValue(myObject);

리플렉션을 사용하여 클래스의 속성과 필드를 조작할 수 있습니다. 값을 가져오거나 설정하는 등의 작업을 수행할 수 있습니다.

C# Reflection 을 이용한 실제 예제

위의 Student Class의 함수명과 변수명을 모두 출력하는 프로그램을 작성해 보도록 하겠습니다.
전체 소스를 보여드리면 다음과 같습니다.

using System;
using System.Reflection;

class Student
{
    // 필드 
    public int age;
    // 메서드 
    public void score()
    {
    }
}

class Program
{
    static void FieldInvestigation(Type t)
    {
        Console.WriteLine("*********Fields*********");
        FieldInfo[] fld = t.GetFields();
        foreach (FieldInfo f in fld)
        {
            Console.WriteLine("-->{0}", f.Name);
        }
    }

    static void MethodInvestigation(Type t)
    {
        Console.WriteLine("*********Methods*********");
        MethodInfo[] mth = t.GetMethods();
        foreach (MethodInfo m in mth)
        {
            Console.WriteLine("-->{0}", m.Name);
        }
    }

    static void Main()
    {
        // Student 정보를  가져오고 이를 Type 변수 t에 로드
        Type t = typeof(Student);
        //모든 변수(필드)명 조사 
        FieldInvestigation(t);
        // 모든 함수(Method)명 조사
        MethodInvestigation(t);
    }
}
C# Reflection: 런타임에서 클래스의 메소드명과 변수명을 조사
그림5. 출력

어떤가요? 런타임중에 Student 클래스의 모든 필드, 메서드명을 출력할 수 있죠?
잘만 활용하면 아주 쉬운 프로그램 작성할 수 있습니다.
변수, 메소드명에 따라 분기되야 하는 프로그램등은 아주 쉽게 코드를 구성할 수 있겠죠?

결론

C# 리플렉션은 코드 작성 및 디버깅을 보다 효율적으로 할 수 있도록 도와주는 강력한 도구입니다. 객체의 유형과 속성 정보에 동적으로 접근하여 코드의 유연성을 향상시킬 수 있습니다. 하지만 C# 리플렉션은 강력한 기능이지만 주의해야 할 점도 있습니다. 너무 남용하면 성능에 부정적인 영향을 미칠 수 있고, 보안 측면에서 취약점을 만들 수도 있습니다. 따라서 신중하게 사용해야 합니다.

Leave a Comment