모든 데이터 형식의 조상인 Object 형식에 GetType() 메소드를 만들어 둠으로써, 파생되는 모든 형식에서 Type을 볼수 있게 되었습니다.
Type 클래스
Object는 다음의 5개 메소드를 가지고 있습니다.
Equals()
GetHashCode()
GetType()
ReferenceEquals()
ToString()
그 말은 곧 모든 데이터 형식이 저 5개의 메소드를 가지고 있다는 뜻입니다. Object는 모든 형식의 조상이기 때문입니다.
그 중 GetType() 메소드는 Type 형식의 결과를 반환합니다. Type은 .NET에 있는 모든 데이터 형식의 정보를 담고 있습니다.
using System;
using System.Reflection;
namespace GetTypeExample
{
class Program
{
static void Main(string[] args)
{
int i = 42;
Type type = i.GetType();
Console.WriteLine(type);
FieldInfo[] fields = type.GetFields(); // 필드 목록 조회
foreach (var field in fields)
{
Console.WriteLine("Type:{0}, Name:{1}", field.FieldType.Name, field.Name);
}
}
}
}
| cs |
위의 예제는 int 형식의 필드 목록을 뽑아볼수 있는 예제입니다.
위의 예제에서는 GetType() 메소드를 이용해서 타입 정보를, GetFields()를 이용해서 FieldInfo를 빼냈지만, 이것 말고도 이용할 수 있는 메소드는 많이 있습니다.
메소드
|
반환 형식
|
설명
|
GetConstructors() | ConstructorInfo[] | 생성자 목록 반환 |
GetEvents() | EventInfo[] | 이벤트 목록 반환 |
GetFields() | FieldInfo[] | 필드 목록 반환 |
GetGenericArguments() | Type[] | 매개 변수 목록 반환 |
GetInterfaces() | Type[] | 인터페이스 목록 반화 |
GetMembers() | MemberInfo[] | 멤버 목록 반화 |
GetMethods() | MethodInfo[] | 메소드 목록 반환 |
GetNestedType() | Type[] | 내장 형식 목록 반환 |
GetProperties() | PropertyInfo[] | 포로퍼티 목록 반환 |
이 외에도 어마어마한 양의 Type 메소드들을 MSDN에서 찾아 볼 수 있습니다.
System.Reflection.BindingFlags 열거형 플래그를 이용해서 검색 조건을 부여할 수가 있습니다(물론 매개변수 없는 메소드도 당연히 가능합니다).
// public 인스턴스 필드 조회
GetFields( BindingFlags.Public | BindingFlags.Instance )
// NonPublic 인스턴스 필드 조회
GetFields( BindingFlags.NonPublic | BindingFlags.Instance )
// public 정적 필드 조회
GetFields( BindingFlags.Public | BindingFlags.Static )
// NonPublic 정적필드 조회
GetFields( BindingFlags.NonPublic | BindingFlags.Static )
처럼 사용 가능합니다.
사용 가능한 플래그들은 다음과 같습니다.
Identified by Accessibility
|
Identified by Binding Argument
|
Identified by Operation
|
---|---|---|
DeclaredOnly
FlattenHierarchy
IgnoreCase
IgnoreReturn
Instance
NonPublic
Public
Static
|
ExactBinding
OptionalParamBinding
|
CreateInstance
GetField
SetField
GetProperty
SetProperty
InvokeMethod
PutDispProperty
PutRefDispProperty
|
이제 예제 프로그램을 한번 작성해 보겠습니다.
결과)
--------Interfaces-------
Name: IComparable
Name: IFormattable
Name: IConvertible
Name: IComparable`1
Name: IEquatable`1
--------Fields-------
Access:protected, Type:Int32, Name:m_value
Access:public, Type:Int32, Name:MaxValue
Access:public, Type:Int32, Name:MinValue
--------Properties-------
--------Methods-------
Type:Int32, Name:CompareTo, Parameter:Object
Type:Int32, Name:CompareTo, Parameter:Int32
Type:Boolean, Name:Equals, Parameter:Object
Type:Boolean, Name:Equals, Parameter:Int32
Type:Int32, Name:GetHashCode, Parameter:
Type:String, Name:ToString, Parameter:
Type:String, Name:ToString, Parameter:String
Type:String, Name:ToString, Parameter:IFormatProvider
Type:String, Name:ToString, Parameter:String, IFormatProvider
Type:Int32, Name:Parse, Parameter:String
Type:Int32, Name:Parse, Parameter:String, NumberStyles
Type:Int32, Name:Parse, Parameter:String, IFormatProvider
Type:Int32, Name:Parse, Parameter:String, NumberStyles, IFormatProvider
Type:Boolean, Name:TryParse, Parameter:String, Int32&
Type:Boolean, Name:TryParse, Parameter:String, NumberStyles, IFormatProvider, Int32&
Type:TypeCode, Name:GetTypeCode, Parameter:
Type:Type, Name:GetType, Parameter:
--------Constructors-------
이와 같이 int 형식의 각종 정보에 대해 정보를 얻어올 수 있습니다.
그럼 이런 리플렉션으로 대체 무얼 할 수 있는 것일까요?
using System;
using System.Reflection;
namespace GetTypeExample
{
class Program
{
static void ShowInterfaces(Type type)
{
Console.WriteLine("--------Interfaces-------");
Type[] interfaces = type.GetInterfaces();
foreach (Type i in interfaces)
Console.WriteLine("Name: {0}", i.Name);
Console.WriteLine();
}
static void ShowFields(Type type)
{
Console.WriteLine("--------Fields-------");
FieldInfo[] fields = type.GetFields(
BindingFlags.NonPublic |
BindingFlags.Public |
BindingFlags.Static |
BindingFlags.Instance);
foreach (FieldInfo field in fields)
{
string accessLevel = "protected";
if (field.IsPublic) accessLevel = "public";
else if (field.IsPrivate) accessLevel = "private";
Console.WriteLine("Access:{0}, Type:{1}, Name:{2}",
accessLevel, field.FieldType.Name, field.Name);
}
Console.WriteLine();
}
static void ShowMethods(Type type)
{
Console.WriteLine("--------Methods-------");
MethodInfo[] methods = type.GetMethods();
foreach (MethodInfo method in methods)
{
Console.Write("Type:{0}, Name:{1}, Parameter:",
method.ReturnType.Name, method.Name);
ParameterInfo[] args = method.GetParameters();
for (int i = 0; i < args.Length; i++)
{
Console.Write("{0}", args[i].ParameterType.Name);
if (i < args.Length - 1)
Console.Write(", ");
}
Console.WriteLine();
}
Console.WriteLine();
}
static void ShowConstructors(Type type)
{
Console.WriteLine("--------Constructors-------");
ConstructorInfo[] constructors = type.GetConstructors();
foreach (ConstructorInfo constructor in constructors)
Console.WriteLine("Name:{0}", constructor.Name);
}
static void ShowProperties(Type type)
{
Console.WriteLine("--------Properties-------");
PropertyInfo[] properties = type.GetProperties();
foreach (PropertyInfo property in properties)
Console.WriteLine("Type:{0}, Name:{1}",
property.PropertyType.Name, property.Name);
Console.WriteLine();
}
static void Main(string[] args)
{
int i = 1;
Type type = i.GetType();
ShowInterfaces(type);
ShowFields(type);
ShowProperties(type);
ShowMethods(type);
ShowConstructors(type);
}
}
}
| cs |
결과)
--------Interfaces-------
Name: IComparable
Name: IFormattable
Name: IConvertible
Name: IComparable`1
Name: IEquatable`1
--------Fields-------
Access:protected, Type:Int32, Name:m_value
Access:public, Type:Int32, Name:MaxValue
Access:public, Type:Int32, Name:MinValue
--------Properties-------
--------Methods-------
Type:Int32, Name:CompareTo, Parameter:Object
Type:Int32, Name:CompareTo, Parameter:Int32
Type:Boolean, Name:Equals, Parameter:Object
Type:Boolean, Name:Equals, Parameter:Int32
Type:Int32, Name:GetHashCode, Parameter:
Type:String, Name:ToString, Parameter:
Type:String, Name:ToString, Parameter:String
Type:String, Name:ToString, Parameter:IFormatProvider
Type:String, Name:ToString, Parameter:String, IFormatProvider
Type:Int32, Name:Parse, Parameter:String
Type:Int32, Name:Parse, Parameter:String, NumberStyles
Type:Int32, Name:Parse, Parameter:String, IFormatProvider
Type:Int32, Name:Parse, Parameter:String, NumberStyles, IFormatProvider
Type:Boolean, Name:TryParse, Parameter:String, Int32&
Type:Boolean, Name:TryParse, Parameter:String, NumberStyles, IFormatProvider, Int32&
Type:TypeCode, Name:GetTypeCode, Parameter:
Type:Type, Name:GetType, Parameter:
--------Constructors-------
이와 같이 int 형식의 각종 정보에 대해 정보를 얻어올 수 있습니다.
그럼 이런 리플렉션으로 대체 무얼 할 수 있는 것일까요?
리플렉션을 이용한 객체 생성
리플렉션을 이용하면 런타임에 특정 형식의 인스턴스를 만들 수 있습니다.
System.Activator 클래스를 사용하면 그것이 가능해 지는데요.
object a = Activator.CreateInstance(typeof(int));
처럼 하면 int형의 인스턴스를 생성하게 됩니다.
제너릭도 가능합니다.
List<int> list = Activator.CreateInstance<List<int>>();
와 같은 형식입니다. 프로퍼티의 값 설정이나 메소드의 호출도 동적으로 가능합니다.
PropertyInfo의 SetValue(), GetValue()메소드, MethodInfo의 Invoke()라는 메소드를 이용하면 말이죠.
using System;
using System.Reflection;
namespace DynamicInstance
{
class Profile
{
public string Name { get; set; }
public string Address { get; set; }
public Profile()
{
Name = ""; Address = "";
}
public Profile(string name, string address)
{
Name = name; Address = address;
}
public void Print()
{
Console.WriteLine("이름:{0}, 주소:{1}", Name, Address);
}
}
class Program
{
static void Main(string[] args)
{
Type type = Type.GetType("DynamicInstance.Profile");
MethodInfo methodInfo = type.GetMethod("Print");
PropertyInfo NameProperty = type.GetProperty("Name");
PropertyInfo AddressProperty = type.GetProperty("Address");
object profile = Activator.CreateInstance(type, "Rachael Mc.Adams", "남양주");
methodInfo.Invoke(profile, null);
profile = Activator.CreateInstance(type);
NameProperty.SetValue(profile, "Babara palvin", null);
AddressProperty.SetValue(profile, "구리시", null);
Console.WriteLine("{0}, {1}",
NameProperty.GetValue(profile, null),
AddressProperty.GetValue(profile, null));
}
}
}
| cs |
결과)
이름:Rachael Mc.Adams, 주소:남양주
Babara palvin, 구리시
댓글 없음:
댓글 쓰기