RSS구독하기:SUBSCRIBE TO RSS FEED
즐겨찾기추가:ADD FAVORITE
글쓰기:POST
관리자:ADMINISTRATOR
리플렉션을 통해서 타입을 컨트롤하는 것은 일반 개발자(컴파일러/프레임웍 등의 개발자가 아닌)에게는 거의 필요가 없거나, 사용을 권장하지 않는 기능입니다. 하지만, 실무를 접하다 보면 부득이하게 필요한 경우가 발생하기 마련이고, 제한적으로 사용하면 도움이 되기에 이러한 팁을 작성해 보았습니다.


// 테스트를 위한 클래스
public class IHavePrivateMember
{
    public IHavePrivateMember()
    {
        this.mySecretName = "Lemon";
    }

    private string mySecretName;
    private void PrintSecretName()
    {
        Console.WriteLine("My secret name is {0}.", this.MySecretName);
    }

    private string MySecretName
    {
        get { return this.mySecretName; }
    }
}


위와 같은 클래스의 private 멤버인 mySecretName 변수, MySecretName 프러퍼티, PrintSecretName 메서드에 접근해 보도록 하겠습니다.

IHavePrivateMember 클래스의 타입을 얻어오는 것에서부터 리플렉션이 시작됩니다. CLR에서 관리되는 모든 타입은 System.Type 클래스의 인스턴스인데, 이 클래스는 객체의 타입을 유지, 관리해주는 많은 멤버들을 가지고 있습니다. 그 중 GetMembers 메서드를 통해서 해당 타입의 멤버들을 MemberInfo 클래스로 가져올 수 있습니다.

MemberInfo[] privateMembers = typeof(IHavePrivateMember).GetMembers(
                BindingFlags.Instance | BindingFlags.NonPublic);


MemberInfo 클래스는 다음과 같은 상속 구조를 가지면서 다른 구체화된 멤버정보 클래스들의 베이스가 됩니다.

사용자 삽입 이미지
GetMembers는 위에서 보이는 MemberInfo를 상속받는 클래스들을 MemberInfo클래스의 배열로 리턴해줌으로써 MemberInfo.MemberType을 살펴보고 이를 적절히 캐스팅해서 사용할 수 있습니다.

if (privateMembers[i].MemberType == MemberTypes.Field)
{
}


이와 같이 타입을 확인후에 해당 클래스로 캐스팅하여 적절한 액션을 취하면 되겠지요. 필드를 대상으로 취할 수 있는 액션은 값을 가져오는 것이니깐 GetValue 정도의 메서드가 적절할 듯 싶습니다. 그런데, GetValue 메서드는 파라메터를 하나 요구하는데요, 이 멤버가 Static 멤버가 아닌, 인스턴스멤버이기 때문에 값을 가져오려면 반드시 인스턴스가 필요하기 때문입니다.

IHavePrivateMember secret = new IHavePrivateMember();
Console.WriteLine("멤버변수 {0} / 값 : {1}",
    privateMembers[i].Name,
    ((FieldInfo)privateMembers[i]).GetValue(secret)
);


이렇게 값을 얻어올 실제 인스턴스를 넘겨줍니다.

하나를 알면 열을 안다고 했던가요? 나머지 타입들도 같은 맥락으로 사용하실 수 있습니다. 메서드는 실행이니까 Invoke, 프러퍼티도 값을 가져오니까 GetValue 이런식으로 사용하시면 됩니다.

콘솔응용프로그램으로 실행되는 전체 소스코드는 아래와 같습니다.

using System;
using System.Reflection;

namespace AccessPrivateMemberSample
{
    internal class Program
    {
        static void Main(string[] args)
        {
            IHavePrivateMember secret = new IHavePrivateMember();

            // 멤버로 검색할 조건을 인자로써 지정해줌
            MemberInfo[] privateMembers = typeof(IHavePrivateMember).GetMembers(
                BindingFlags.Instance | BindingFlags.NonPublic);

            for (int i = 0; i < privateMembers.Length; i++)
            {
                if (privateMembers[i].MemberType == MemberTypes.Field)
                {
                    Console.WriteLine("멤버변수 {0} / 값 : {1}",
                        privateMembers[i].Name,
                        ((FieldInfo)privateMembers[i]).GetValue(secret)
                    );
                }
                else if (privateMembers[i].MemberType == MemberTypes.Property)
                {
                    Console.WriteLine("프러퍼티 : {0} / 값 : {1}",
                        privateMembers[i].Name,
                        ((PropertyInfo)privateMembers[i]).GetValue(secret, null)
                    );
                }
                else if (privateMembers[i].MemberType == MemberTypes.Method)
                {
                    MethodInfo mi = privateMembers[i] as MethodInfo;
                    if (mi != null && mi.GetParameters().Length == 0)
                    {
                        Console.WriteLine("메서드 {0} 실행 ----------", mi.Name);
                        mi.Invoke(secret, null);
                        Console.WriteLine("메서드 {0} 실행 끝 --", mi.Name);
                    }
                }
            }
        }
    }

    // 테스트를 위한 클래스
    public class IHavePrivateMember
    {
        public IHavePrivateMember()
        {
            this.mySecretName = "Lemon";
        }

        private string mySecretName;
        private void PrintSecretName()
        {
            Console.WriteLine("My secret name is {0}.", this.MySecretName);
        }

        private string MySecretName
        {
            get { return this.mySecretName; }
        }
    }
}


결과
메서드 PrintSecretName 실행 ----------
My secret name is Lemon.
메서드 PrintSecretName 실행 끝 --
메서드 get_MySecretName 실행 ----------
메서드 get_MySecretName 실행 끝 --
메서드 Finalize 실행 ----------
메서드 Finalize 실행 끝 --
메서드 MemberwiseClone 실행 ----------
메서드 MemberwiseClone 실행 끝 --
프러퍼티 : MySecretName / 값 : Lemon
멤버변수 mySecretName / 값 : Lemon
계속하려면 아무 키나 누르십시오 . . .

2009/03/31 20:27 2009/03/31 20:27
http://lemonwidz.com/tc/trackback/21
«이전  1 ... 2 3 4 5 6 7 8 9 10 ... 23  다음»
전체 (23)
사진이야기 (4)
프로그래밍 (18)
  1. Nyaonge's Home  2011
    [C#] ?? 연산자(물음표 두개)
  1. 2012/03 (1)
  2. 2011/12 (2)
  3. 2009/07 (1)
  4. 2009/04 (1)
  5. 2009/03 (9)