오늘은 reflection과 Attribute에 대해 알아보고자 합니다.
1주 동안 만든 팀 과제를 제출하고 다른 팀들의 발표를 듣던 중
reflection을 사용하는 코드를 보게 되었습니다.
이름만 들어보고 사용을 한 번도 안 해봐서 이참에
어떻게 사용하는지 간단하게 찾아보고 정리해 봤습니다.
자료를 찾다 보니 다들 Attribute를 묶어서 설명하더군요.
일단 이것도 함께 정리해 봤습니다.
reflection
런타임 중에 객체의 형식을 가져와 사용할 수 있게 해주는 기능입니다.
관련 메서드들을 claude를 통해 깔끔하게 표로 정리해 달라고 해봤습니다.
타입을 가져오는 방식은 3가지로 나뉩니다.
메서드 | 반환 타입 | 설명 | 예제 |
GetType() | Type | 객체의 실제 런타임 타입을 반환 | string str = "Hello"; Type t = str.GetType(); |
typeof() | Type | 컴파일 타임에 타입 정보를 가져옴 | Type t = typeof(string); |
Type.GetType(string) | Type | 문자열로 된 타입 이름으로 Type을 가져옴 | Type t = Type.GetType("System.String"); |
자주 사용되는 GetType들 입니다.
메서드 | 반환 타입 | 설명 | 예제 |
GetMethods() | MethodInfo[] | 모든 public 메서드 정보를 가져옴 | var methods = type.GetMethods(); |
GetMethod(string) | MethodInfo | 특정 이름의 public 메서드 정보를 가져옴 | var method = type.GetMethod("ToString"); |
GetProperties() | PropertyInfo[] | 모든 public 속성 정보를 가져옴 | var props = type.GetProperties(); |
GetProperty(string) | PropertyInfo | 특정 이름의 public 속성 정보를 가져옴 | var prop = type.GetProperty("Length"); |
GetFields() | FieldInfo[] | 모든 public 필드 정보를 가져옴 | var fields = type.GetFields(); |
GetField(string) | FieldInfo | 특정 이름의 public 필드 정보를 가져옴 | var field = type.GetField("fieldName"); |
GetConstructors() | ConstructorInfo[] | 모든 public 생성자 정보를 가져옴 | var ctors = type.GetConstructors(); |
GetConstructor(Type[]) | ConstructorInfo | 특정 매개변수를 가진 생성자 정보를 가져옴 | var ctor = type.GetConstructor(new Type[] { typeof(string) }); |
GetCustomAttributes() | object[] | 모든 커스텀 속성을 가져옴 | var attrs = type.GetCustomAttributes(); |
GetInterface(string) | Type | 특정 이름의 인터페이스 타입을 가져옴 | var iface = type.GetInterface("IDisposable"); |
GetInterfaces() | Type[] | 구현된 모든 인터페이스를 가져옴 | var ifaces = type.GetInterfaces(); |
가져올 형식에 추가 옵션 (BindingFlags)을 걸 수 있습니다.
플래그 | 설명 |
Public | public 멤버만 |
NonPublic | private/protected 멤버 |
Instance | 인스턴스 멤버 |
Static | 정적 멤버 |
DeclaredOnly | 상속된 멤버 제외 |
IgnoreCase | 멤버 이름 대소문자 구분 없이 |
// 모든 private 인스턴스 필드 가져오기
var privateFields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
// 상속된 것을 제외한 public 메서드만 가져오기
var declaredPublicMethods = type.GetMethods(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance);
보통 가져온 객체 형식을 토대로
Activator라는 클래스를 사용하여 객체의 인스턴스를 동적으로 생성하고,
GetValue와 SetValue를 통해 값을 제어하여 사용합니다.
public class Person
{
public string Name { get; set; }
private int age;
public string Address { get; set; }
}
public class ReflectionExample
{
public void DemoGetSetValues()
{
// Activator로 인스턴스 생성
Type type = typeof(Person);
Person person = (Person)Activator.CreateInstance(type);
// 속성(Property) 값 설정/가져오기
PropertyInfo nameProperty = type.GetProperty("Name");
nameProperty.SetValue(person, "John"); // 값 설정
string name = (string)nameProperty.GetValue(person); // 값 가져오기
Console.WriteLine($"Name: {name}");
// private 필드 값 설정/가져오기
FieldInfo ageField = type.GetField("age",
BindingFlags.NonPublic | BindingFlags.Instance);
ageField.SetValue(person, 25); // private 필드 값 설정
int age = (int)ageField.GetValue(person); // private 필드 값 가져오기
Console.WriteLine($"Age: {age}");
}
}
Attribute는 주로
- 플러그인 시스템 구현
- 직렬화/역직렬화
- DI(종속성 주입) 컨테이너
등에 사용된다고 합니다.
※ Reflection을 사용하기 위해서는
using System.Reflection; 을 추가해 줘야 합니다.
Attribute
c# 코드에 추가할 수 있는 메타데이터
메타데이터?
다른 데이터를 설명해 주는 데이터
주석은 컴파일 시 실행파일에서 제거되지만,
어트리뷰트는 실행파일 안에 저장되어 런타임 중에도 읽을 수 있습니다.
[Obsolete("ThisClass is obsolete. Use ThisClass2 instead.")]
public class ThisClass
{
}
//Obsolete는 코드가 더 이상 사용되지 않으며
//더 이상 사용되어서는 안된다고 알리기 위해 사용하는 Attribute
// 마이크로 소프트 공식 문서 코드 발췌
이 외에도 유니티에서의 SerializeField가 Attribute의 예에 해당한다고 합니다.
오...
정해진 Attribute 말고 직접 만들어 사용할 수는 없을까요?
당연히 가능합니다.
public class GotchaAttribute : Attribute
{
public GotchaAttribute(string str)
{
}
}
// C#에서 Attribute는 Attribute 기본 클래스에서 상속되는 클래스
// 마이크로 소프트 공식 문서 코드 발췌
public class Explane
{
// 만든 GotchaAttribute 어트리뷰트 사용, Gotcha 뒤 Attribute는 생략 가능
[Gotcha("string이라서 문자열 ")]
}
마무리
reflection과 함께 활용하여 런타임으로 Attribute에 접근,
동적 할당하는 방식으로 자주 사용되어 둘을 함께 설명하나 봅니다.
왜 같이 설명했는지 이제야 이해가 가는군요.
최근 유니티에서 동적으로 어떻게 연동해야 할지 고민 중이었는데
한번 적용해 코드를 짜봐야 할 것 같습니다.
여기에 추가로 직렬화하여 데이터 저장 때도 사용되는 듯 하니 ;;
배울수록 모르는 게 너무 많네요;;
참고한(혹은 참고하면 좋은) 자료
https://youtu.be/y96OaJXKM7o?si=TuWnqlQyhg8dUSuN
https://youtu.be/x0CayxlgKPE?si=8JCfdF0ZL--1EvLp
https://youtu.be/aDGvR5Fk9J4?si=ahyyMQ-ayYzaz-N3
https://learn.microsoft.com/ko-kr/dotnet/csharp/advanced-topics/reflection-and-attributes/
특성 및 리플렉션 - C#
특성을 사용하여 C#에서 메타데이터 또는 선언적 정보를 코드와 연결합니다. 특성은 리플렉션을 사용하여 런타임에 쿼리할 수 있습니다. 리플렉션은 C#에서 어셈블리, 모듈 및 형식을 설명하는
learn.microsoft.com
'C#' 카테고리의 다른 글
C# 얕은 복사(Shallow Copy) 깊은 복사(Deep Copy) (0) | 2024.12.09 |
---|---|
2024 내일 배움캠프(Unity_6기) _ 사전캠프 7일차(08.21) : String 과 StringBuilder에 대해 알아보자 (0) | 2024.08.21 |
2024 내일 배움캠프(Unity_6기) _ 사전캠프 6일차(08.20) : C# 문자열 보간 에 대해 알아보자 (0) | 2024.08.20 |
2024 내일 배움캠프(Unity_6기) _ 사전캠프 5일차(08.19) - Random에 대해 알아보자 (0) | 2024.08.19 |
2024 내일 배움캠프(Unity_6기) _ 사전캠프 4일차(08.16) - C# 문법 기초 : Convert, Parse, TryParse (0) | 2024.08.16 |