One_KWS

Reflection 본문

C#

Reflection

One-Kim 2023. 2. 14. 13:21

Reflection

리플렉션은 객체의 Type 정보를 들여다보는 기능이다. Reflection을 이용하면 런타임중 객체의 Type, 이름부터 프로퍼티, 메소드, 이벤트, 필드 목록까지 모두 확인할 수 있다. 또한 동적으로 인스턴스를 생성할 수도 있고 메소드를 호출할 수도 있다. 새로운 데이터 형식을 동적으로 생성하는 것도 가능하다.

 

C#의 모든 데이터는 Object를 상속받고 있다. 즉, 모든 데이터 형식은 Object 형식이 갖고 있는 다음의 메소드를 물려받아 갖고 있다.

  • Equals()
  • GetHashCode()
  • GetType()
  • ReferenceEquals()
  • ToString()

C#에서는 어떤 형식이든지 기본적으로 위의 함수들을 가지고 있다.

위의 다섯 개 메소드 중에 GetType() 메소는 객체의 Type 정보를 반환하는 기능을 한다. 모든 데이터 형식이 GetType() 메소드를 갖고 있기 때문에 어떤 객체에 대해서도 이 메소드를 호출하여 그 객체의 형식 정보를 얻어낼 수 있다.

Type은 .NET에서 사용되는 데이터 형식의 모든 정보를 담고 있다. 이름, 소속되어 있는 어셈블리의 이름, 프로퍼티 목록, 메소드 목록, 필드 목록, 이벤트 목록, 심지어는 이 형식이 상속하고 있는 인터페이스의 목록까지도 갖고 있다. 

 

Type 메소드

아래는 Type의 메소드들이다. 이외에도 다양한 메소드들이 있으면 MSDN을 통해 확인할 수 있다. 

메소드 반환 형식 설명
GetConstructor() ConstructorInfo[] 해당 형식의 모든 생성자 목록을 반환한다.
GetEvents() EventInfo[] 해당 형식의 이벤트 목록을 반환한다.
GetFields() Type[] 해당 형식의 필드 목록을 반환한다.
GetMembers() MemberInfo[] 해당 형식의 멤버 목록을 반환한다.
GetMethods() MethodInfo[] 해당 형식의 메소드 목록을 반환한다.
GetProperties() PropertyInfo[] 해당 형식의 프로퍼티 목록을 반환한다.

 

예시 코드

아래 코드는 User 클래스를 만들고 Reflection을 이용하여 User 클래스의 필드값을 가져오고 함수를 호출하는 예제이다. GetFields()를 통해 필드들의 이름과 값을 가져올 수 있고 GetMethod()를 이용하여 해당 클래스 내에 함수를 호출할 수 있다.

using System;
using System.Reflection;

namespace ReflectionExample {
    public class User {
        public string name;
        public bool isMarried;
        public int age;

        public User(string name, bool isMarried, int age) {
            this.name = name;
            this.isMarried = isMarried;
            this.age = age;
        }

        public void PrintUserInfo() {
            Console.WriteLine("User Info");
            Console.WriteLine($"User Name : {name}");
            Console.WriteLine($"Is user married? : {isMarried}");
            Console.WriteLine($"User Age : {age}");
        }
    }

    class Program {
        static void Main(string[] args) {
            User user = new User("KWS", false, 31);

            Type type = user.GetType();
            var fieldInfo = type.GetFields(); //필드의 정보를 가져온다

            foreach(var field in fieldInfo) {
                Console.WriteLine($"field name : {field.Name}, field value : {field.GetValue(user)}");
            }

            MethodInfo methodInfo = type.GetMethod("PrintUserInfo"); //메소드 정보를 가져온다.
            methodInfo.Invoke(user, null);
        }
    }
}

실행 결과는 아래와 같다.

 

BindingFlags

Type 메소드에 매개변수 옵션을 추가하여 검색 옵션을 지정할 수 있다. public 항목만 조회할 수도 있고, public 이외의 항목만 조회할 수도 있으며 public과 public 이외의 항목을 같이 조회할 수도 있다. static 항목만 조회할 수도 있고 인스턴스 항목만 조회할 수도 있다. 또는 모든 조건들을 포함하는 조건을 만들 수도 있다. 이러한 검색 옵션은 System.Reflection.BindingFlags 열거형을 이용해서 구성된다. (BindingFlags 매개 변수를 받지 않으면 public 멤버만 반환한다.)

 

using System;
using System.Reflection;

namespace Reflection_Test {
    public class User {
        public string name;
        private bool isMarried;
        protected int age;

        public User(string name, bool isMarried, int age) {
            this.name = name;
            this.isMarried = isMarried;
            this.age = age;
        }

        private void PrintUserInfo() {
            Console.WriteLine("User Info");
            Console.WriteLine($"User Name : {name}");
            Console.WriteLine($"Is user married? : {isMarried}");
            Console.WriteLine($"User Age : {age}");
        }
    }

    class Program {
        static void Main(string[] args) {
            User user = new User("KWS", false, 31);

            Type type = user.GetType();
            // user 인스턴스 필드 중 public이 아닌 필드들의 정보만 가져온다
            var fieldInfo = type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
            foreach(var field in fieldInfo) {
                Console.WriteLine($"field name : {field.Name}, field value : {field.GetValue(user)}");
            }

            // "PrintUserInfo" 메소드가 public이 아닐 경우에만 정보를 가져온다.
            MethodInfo methodInfo = type.GetMethod("PrintUserInfo", BindingFlags.Instance | BindingFlags.NonPublic);
            methodInfo.Invoke(user, null);
        }
    }
}

 

결과는 아래와 같다.  User 클래스의 name이 public이기 때문에 isMarried와 age만 가져온 것을 볼 수 있다. PrintUserInfo() 메소드도 private이기 때문에 정보를 가져와서 호출할 수 있다.(public이었다면 GetMethod() 결과로 null 값이 리턴된다.)

'C#' 카테고리의 다른 글

==, Equals(), ReferenceEquals()  (0) 2023.05.21
박싱(Boxing) & 언박싱(Unboxing)  (0) 2023.05.07
CLR, IL, JIT  (0) 2023.03.29
Value Type, Reference Type  (0) 2023.03.01