프로그래밍/C# 2009/03/31 20:27
리플렉션을 통해서 타입을 컨트롤하는 것은 일반 개발자(컴파일러/프레임웍 등의 개발자가 아닌)에게는 거의 필요가 없거나, 사용을 권장하지 않는 기능입니다. 하지만, 실무를 접하다 보면 부득이하게 필요한 경우가 발생하기 마련이고, 제한적으로 사용하면 도움이 되기에 이러한 팁을 작성해 보았습니다.
// 테스트를 위한 클래스
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 클래스는 다음과 같은 상속 구조를 가지면서 다른 구체화된 멤버정보 클래스들의 베이스가 됩니다.

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
계속하려면 아무 키나 누르십시오 . . .
My secret name is Lemon.
메서드 PrintSecretName 실행 끝 --
메서드 get_MySecretName 실행 ----------
메서드 get_MySecretName 실행 끝 --
메서드 Finalize 실행 ----------
메서드 Finalize 실행 끝 --
메서드 MemberwiseClone 실행 ----------
메서드 MemberwiseClone 실행 끝 --
프러퍼티 : MySecretName / 값 : Lemon
멤버변수 mySecretName / 값 : Lemon
계속하려면 아무 키나 누르십시오 . . .
http://lemonwidz.com/tc/trackback/21



0