본문 바로가기

.NET/C# Reflection

[C# Reflection] GetField(), GetFields() 메서드와 FieldInfo 클래스

Type 클래스에 대해 GetField() 또는 GetFields() 메서드를 사용해서 타입에 속한 필드의 정보를 가져올 수 있으며 필드의 정보는 FieldInfo 클래스의 인스턴스 형태로 반환된다. 오늘은 이들에 대해 알아보자.

 

먼저 GetField()와 GetFields() 등 리플렉션에서 타입에 속한 멤버를 검색해서 가져오기 위한 메서드를 사용하려면 BindingFlags에 대해 알아둘 필요가 있다. BindingFlags System.Reflection 네임스페이스에 정의되어 있는 enum으로, 검색 조건들을 열거형으로 나타낸 것이며, 비트 조합을 허용하는 Flags 특성이 적용되어 있어 비트 연산자를 사용해 여러 조건을 조합할 수 있다.

 

우리가 앞으로 주로 사용할 바인딩 플래그는 다음과 같다.

BindingFlags Value Description
Default 0 바인딩 플래그를 지정하지 않는다.
IgnoreCase 1 이름의 대/소문자를 구분하지 않도록 한다. (이름으로 검색할 때)
DeclaredOnly 2 지정된 형식의 계층에 수준에 속하는 멤버만 포함시킨다. 즉, 부모 클래스로부터 상속된 멤버는 포함시키지 않는다.
Instance 4 인스턴스 멤버를 포함시킨다.
Static 8 Static(정적) 멤버를 포함시킨다.
Public 16 Public 멤버를 포함시킨다.
NonPublic 32 Public이 아닌 멤버를 포함시킨다.

만약 Public인 인스턴스에 대해 검색하려면 BindingFlags를 'BindingFlags.Public | BindingFlags.Instance'와 같이 Or 하여 지정할 수 있다.

바인딩 플래그는 앞으로도 계속 사용되니 잘 숙지해 놓는 것이 좋다.

 

이번에 알아볼 메서드인 GetField()와 GetFields()는 둘 다 FieldInfo를 반환하긴 하나, 이름에서 알 수 있듯 GetField()는 FieldInfo를 반환하며, GetFields()는 FieldInfo[]를 반환한다. 두 메서드 모두 여러 가지 형태로 오버로드되어 있으며, 필요에 따라 사용할 수 있다.

 

0. FieldInfo 클래스

FieldInfo 클래스는 필드의 정보를 담을 수 있도록 만들어진 클래스이며, GetField()와 GetFields()로 검색된 필드의 정보가 FieldInfo 클래스의 개체에 담겨 반환된다.

FieldInfo에는 Name, IsPublic, IsPrivate, IsStatic, FieldType 등 여러가지 속성과, GetValue(), SetValue() 등의 메서드가 있다. 속성이나 메서드에 대한 설명은 처음 사용할 때마다 하겠지만, 마이크로소프트 도큐먼트에 정리가 잘 되어 있으므로 궁금하면 아래 링크에서 찾아보도록 하자.

 

FieldInfo 클래스 (System.Reflection)

필드의 특성을 검색하고 필드 메타데이터에 대한 액세스를 제공합니다.Discovers the attributes of a field and provides access to field metadata.

docs.microsoft.com

 

1. GetField(string), GetField(string, BindingFlags) - 필드를 이름으로 가져오기

이름으로 필드를 검색하기 위해 위 두 가지 메서드를 사용할 수 있다. 지정된 이름에 해당하는 필드가 있는 경우 해당 필드에 대한 FieldInfo 개체를 반환하며, 찾지 못한 경우 null을 반환한다.

 

GetField(string)은 Public인 필드에 한해서만 검색하므로, Public이 아닌 필드에 대해 검색하려면 GetField(string, BindingFlags)를 사용한다.

using System.Reflection;
using System;

namespace Project
{
	class Program
    {
    	class MyClass
        {
        	public int FieldA;
            public double FieldB;
            char fieldC;
            float fieldD;
        }
        
    	static void Main(string[] args)
        {
        	var obj = new MyClass();
            
        	Console.Write("검색할 필드를 입력하세요 : ");
            var name = Console.ReadLine();
            
            // Public, NonPublic, Instance를 조건으로 검색
            var fieldInfo = obj.GetType().GetField(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
            
            // obj.GetType() 대신 typeof(MyClass)로 Type을 가져와도 된다.
            // var fieldInfo = typeof(MyClass).GetField(...);
            
            if(fieldInfo != null)
            	Console.WriteLine($"검색된 필드 : {fieldInfo.Name}");
            else 
            	Console.WriteLine("존재하지 않는 필드입니다.");
        }
    }
}

FieldInfo.Name 속성은 필드의 이름을 string 형식으로 돌려준다.

 

GetField()를 사용하기 전에 반드시 숙지해야 할 것

만약 GetField() 메서드는 하나의 FieldInfo만을 반환할 수 있다. 따라서 지정된 검색 조건으로 두 개 이상의 필드가 검색되는 경우 메서드는 AmbiguousMatchException 예외를 던질 것이다. 같은 이름의 필드는 당연히 두 개 이상 존재할 수 없지만, 만약 BindingFlags.IgnoreCase를 사용해 대/소문자를 구분하지 않고 검색하게 된다면 여러 개의 필드가 검색 결과로 선정되는 것도 충분히 가능하다. 가령 apple이라는 이름의 필드와 Apple이라는 이름의 필드가 있을 때, C#은 식별자의 대/소문자를 구분하기 때문에 코드 상의 문제는 전혀 없지만 BindingFlags.IgnoreCase 옵션은 두 필드의 이름을 같다고 볼 것이다.

 

2. GetFields(), GetFields(BindingFlags) - 검색 조건을 만족하는 필드를 모두 가져오기

GetField()와 다르게 GetFields()는 검색 조건에 해당되는 필드를 모두 가져온다.

using System.Reflection;
using System;

namespace Project
{
	class Program
    {
    	class MyClass
        {
        	public int FieldA;
            public double FieldB;
            char fieldC;
            float fieldD;
        }
        	
    	static void Main(string[] args)
        {
        	var fields = typeof(MyClass).GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
            
            foreach(var field in fields)
            {
            	Console.WriteLine($"{field.FieldType.Name} {field.Name}");
            }
        }
    }

 

FieldInfo.FieldType 속성은 필드의 형식을 Type 형태로 돌려준다.