반응형
리플렉션
- 객체의 형식(Type) 정보를 들여다보는 기능이다.
- 이 기능을 이용하면 프로그램 실행 중에 객체의 형식 이름부터 프로퍼티 목록, 메서드 목록, 필드, 이벤트 목록까지 모두 열어볼 수 있다.
- 형식의 이름만 있다면 동적으로 인스턴스를 만들 수 있다.
- 새로운 데이터 형식을 동적으로 만들 수도 있다.
Object.GetType() 메서드와 Type 클래스
- Object는 모든 데이터 형식의 조상이기 때문에 모든 데이터 형식은 다음 메서드를 물려받는다.
- Equals()
- GetHashCode()
- GetType()
- ReferenceEquals()
- ToString()
- 위의 메서드 중 GetType() 메서드를 이용해서 객체의 형식 정보를 얻어낼 수 있다.
- GetType() 메서드는 Type 형식의 결과를 반환한다.
- Type 형식은 다음과 같은 데이터 형식의 정보를 담고있다.
- 형식 이름
- 소속되어 있는 어셈블리 이름
- 프로퍼티 목록
- 메서드 목록
- 필드 목록
- 이벤트 목록
- 인터페이스의 목록
예제 - 간단한 리플렉션 사용
int a = 0;
Type type = a.GetType();
FieldInfo[] fields = type.GetFields(); // 필드 목록 조회
foreach (var field in fields)
{
Console.WriteLine("Type:{0}, Name:{1}", field.FieldType.Name, field.Name);
}
- int에 커서를 두고 F12로 확인한 결과 field 값은 MaxValue와 MinValue만 있는걸 확인할 수 있다.
- 해당 형식의 필드 목록을 반환하는 GetFields 메서드를 이용해서 Int32에 있는 필드 목록을 출력한 예제다.
메서드 | 반환 형식 | 설명 |
GetConstructors() | ConstructorInfo[] | 해당 형식의 모든 생성자 목록을 반환한다. |
GetEvents() | EventInfo[] | 해당 형식의 이벤트 목록을 반환한다. |
GetFields() | FieldInfo[] | 해당 형식의 필드 목록을 반환한다. |
GetGenericArguments() | Type[] | 해당 형식의 형식 매개 변수 목록을 반환한다. |
GetInterfaces() | Type[] | 해당 형식의 상속하는 인터페이스 목록을 반환한다. |
GetMembers() | MemberInfo[] | 해당 형식의 멤버 목록을 반환한다. |
GetMethods() | MethodInfo[] | 해당 형식의 메서드 목록을 반환한다. |
GetNestedTypes() | Type[] | 해당 형식의 내장 형식 목록을 반환한다. |
GetProperties() | PropertyInfo[] | 해당 형식의 프로퍼티 목록을 반환한다. |
예제 - 검색 옵션 입력
Type type = a.GetType();
// public 인스턴스 필드 조회
var fields1 = type.GetFields(BindingFlags.Public | BindingFlags.Instance);
// 비(非) public 인스턴스 필드 조회
var fields2 = type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
// public 정적 필드 조회
var fields3 = type.GetFields(BindingFlags.Public | BindingFlags.Static);
// 비(非) public 정적 필드 조회
var fields4 = type.GetFields(BindingFlags.NonPublic | BindingFlags.Static);
- 위의 검색옵션을 통해 public 형태의 항목을 조회할지 말지, static 형태의 항목을 조회할지 말지를 정할 수 있다.
리플렉션을 이용한 객체 생성 및 사용방법
- 리플렉션을 이용해서 동적으로 인스턴스를 만들기 위해서는 System.Activator 클래스가 필요하다.
- 인스턴스를 만들고자 하는 형식의 Type 객체를 매개 변수로 넘기면, Activator.CreateInstance() 메서드는 입력받은 형식의 인스턴스를 생성하여 반환한다.
object a = Activator.CreateInstance(typeof(int)); |
- 객체의 프로퍼티에 값을 할당하는 것도 동적으로 할 수 있다.
- Type.GetProperties()의 반환 형식인 PropertyInfo 객체는 SetValue()와 GetValue() 메서드를 갖고 있다.
- GetValue()를 호출하면 프로퍼티로부터 값을 읽을 수 있고, SetValue()를 호출하면 프로퍼티에 값을 할당할 수 있다.
예제 - 프로퍼티 GetValue, SetValue 메서드 사용 O
- Profile 클래스
class Profile
{
public string Name { get; set; }
public string Phone { get; set; }
}
- 코드
Type type = typeof(Profile);
Object profile = Activator.CreateInstance(type);
PropertyInfo name = type.GetProperty("Name"); // 1
PropertyInfo phone = type.GetProperty("Phone");
name.SetValue(profile, "박찬호", null); // 2
phone.SetValue(profile, "123-4567", null);
Console.WriteLine("{0}, {1}", name.GetValue(profile, null), phone.GetValue(profile, null));
- Type.GetProperty() 메서드는 특정 이름의 프로퍼티를 찾아 그 프로퍼티의 정보를 담은 하나의 PropertyInfo 객체만을 반환한다.
- SetValue()와 GetValue()의 마지막 매개 변수는 인덱서의 인덱스를 위해 사용된다. 프로퍼티는 인덱서가 필요없으므로 위 예제에서 null로 할당해주었다.
인덱서란?
예제 - 프로퍼티 GetValue, SetValue 메서드 사용 X
Profile 클래스
class Profile
{
public string Name { get; set; }
public string Phone { get; set; }
public void Print()
{
Console.WriteLine("{0}, {1}", Name, Phone);
}
}
- 코드
Type type = typeof(Profile);
Profile profile = Activator.CreateInstance(type) as Profile; // 1
profile.Name = "박찬호";
profile.Phone = "123-4567";
MethodInfo method = type.GetMethod("Print"); // 2
method.Invoke(profile, null); //3
- 직접 객체 생성하려는 클래스로 형 변환을 한 후에 프로퍼티에 접근이 가능하다.
- MethodInfo 클래스를 이용하면 메서드도 사용할 수 있다.
- null 매개 변수가 오는 자리에는 Invoke() 메서드가 호출할 메서드의 매개 변수가 와야 한다. Profile.Print() 메서드는 매개 변수가 없기 때문에 null을 넘겨주었다.
리플렉션 활용 (뇌피셜)
- 지금까지 공부한 내용인 리플렉션, 인덱서를 바탕으로 xml을 파싱하고 파싱한 내용을 출력하는 코드를 작성해보았다. (이러한 상황에 리플렉션이 활용될거다 라는 내 뇌피셜을 바탕으로 만들었다.)
xml 데이터
<?xml version="1.0" encoding="UTF-8"?>
<PersonalInfo>
<person code="CM001">
<name>홍길동</name>
<sex>남자</sex>
<regNod>123456-1234567</regNod>
<tel>02-123-1234</tel>
<address>
서울
</address>
</person>
<person code="CM002">
<name>김길수</name>
<sex>남자</sex>
<regNod>654321-7654321</regNod>
<tel>03-321-4321</tel>
<address>
부산
</address>
</person>
<person code="CF001">
<name>홍길자</name>
<sex>여자</sex>
<regNod>121212-2323232</regNod>
<tel>031-1111-2222</tel>
<address>
인천
</address>
</person>
</PersonalInfo>
- 위의 데이터에서 person 태그의 code 속성을 기준으로 name, sex, regNode, tel, address의 값을 인덱서를 이용하여 클래스에 저장할 예정이다.
인덱서 및 인적 데이터를 저장할 클래스
class PersonalInfo : IEnumerable
{
private Dictionary<string, Person> data = new Dictionary<string, Person>();
[IndexerNameAttribute("PersonIndexer")]
public Person this[string code]
{
get
{
if (data.ContainsKey(code))
{
return data[code];
}
else
{
throw new Exception("없는 code입니다.");
}
}
set
{
if (value == null)
{
throw new ArgumentNullException("인덱서 오류");
}
else
{
if (data.ContainsKey(code))
{
data[code] = value;
}
else
{
data.Add(code, value);
}
}
}
}
/// <summary>
/// IEnumerable 구현
/// </summary>
/// <returns></returns>
public IEnumerator GetEnumerator()
{
foreach (var result in data)
{
// yield : 데이터를 하나씩 리턴할 때 사용
yield return result.Value;
}
}
}
class Person
{
public string name { get; set; }
public string sex { get; set; }
public string regNod { get; set; }
public string tel { get; set; }
public string address { get; set; }
}
xml 파싱 및 파싱한 내용 출력 코드
XmlDocument xml = new XmlDocument();
xml.Load(@"D:\Study\C#_Restudy\CSharp_Study\Reflection_Example\Reflection_Example\AddressBook.xml");
XmlNodeList xmlList = xml.SelectNodes("PersonalInfo/person");
PersonalInfo personalInfo = new PersonalInfo();
foreach (XmlNode items in xmlList)
{
PropertyInfo propertyInfo = typeof(PersonalInfo).GetProperty("PersonIndexer");
string code = items.Attributes["code"].Value;
Person person = new Person();
foreach(XmlNode item in items.ChildNodes)
{
person.GetType().GetProperty(item.Name).SetValue(person, item.InnerText.Trim(), null);
}
propertyInfo.SetValue(personalInfo, person, new object[] { code });
}
// 출력
foreach (var personData in personalInfo)
{
var personList = personData.GetType().GetProperties();
foreach (var item in personList)
{
Console.WriteLine($"{item.Name} : {item.GetValue(personData, null)}");
}
Console.WriteLine();
}
결과
반응형
'C# > Study' 카테고리의 다른 글
[복습]애트리뷰트 - Attribute, C# (0) | 2021.01.01 |
---|---|
[복습] 인덱서 - C# (0) | 2020.12.21 |
[복습] LINQ - C#, 링크 ,링큐 (0) | 2020.12.18 |
[복습] Delegate - C#, CSharp, 씨샵, 델리게이트, 대리자 (0) | 2020.12.15 |
[C# 공부] Thread(쓰레드) - 비동기 호출, Delegate - 짱우의 코딩일기 - 티스토리 (0) | 2020.04.07 |