2022.08.16 경일 메타버스 20주차 1일 수업내용. 리플렉션과 애트리뷰트, 그리고 dynamic 형식(자습)
2022. 08. 16 경일 메타버스 20주차 1일 수업 1, 2교시 발표 준비
2022. 08. 16 경일 메타버스 20주차 1일 수업 1, 2교시 발표 준비 공유 문서
자료 : 교과서 “이것이 C#이다” ch.16 리플렉션과 애트리뷰트 p. 547
코드 자체의 데이터(메타 데이터)를 다루는 기법
p. 549 ~ 565
객체의 형식(Type) 정보를 들여다보는 기능
런타임에 형식 정보를 다룰 수 있게 한다.
리플렉션으로 가능한 것
프로그램 실행 중(런타임) 객체의 모든 것(형식 이름, 프로퍼티 목록, 메소드 목록, 필드, 이벤트 목록 등)을 열어볼 수 있다.
동적으로 인스턴스를 만들고, 그 인스턴스의 메소드를 호출할 수 있다.
동적으로 새로운 데이터 형식을 만들 수 있다.
p. 549
모든 데이터 형식의 조상
상속해주는 메소드
Equals()
GetHashCode()
ReferenceEquals()
ToString()
GetType()
p. 549 ~ 556
객체의 형식 정보를 반환
Type 형식의 결과를 반환
int 형식의 필드를 조회, 출력하는 예시 코드
int a = 0;
Type type = a.GetType();
FieldInfo[] fields = type.GetFields();
foreach (FieldInfo field in fields)
Console.WriteLine("Type:{0}, Name{1}", field.FieldType.Name, field.Name); // int
Object.GetType() 메소드를 사용하지 않고 형식 정보를 얻는 방법
Object.GetType() 메소드는 인스턴스가 있어야 호출 가능
typeof 연산자, Type.GetType() 메소드
typeof 연산자
형식의 식별자를 인수로 받는다.
Type.GetType() 메소드
형식의 전체 이름(네임스페이스를 포함한 형식 이름)을 인수로 받는다.
예시 코드
Type a = typeof(int);
Console.WriteLine(a.FullName); // int
Type b = Type.GetType("System.Int32");
Console.WriteLine(b.FullName); // System.Int32
p. 549 ~ 551
.NET에서 사용되는 데이터 형식의 모든 정보
주요 메소드
메소드 | 반환 형식 | 설명 |
---|---|---|
GetConstructors() | ConstructorInfo[] | 해당 형식의 모든 생성자 목록 반환 |
GetEvents() | EventInfo[] | 해당 형식의 이벤트 목록 반환 |
GetFields() | FieldInfo[] | 해당 형식의 필드 목록 반환 |
GetGenericArguments() | Type[] | 해당 형식의 형식 매개변수 목록 반환 |
GetInterfaces() | Type[] | 해당 형식이 상속하는 인터페이스 목록 반환 |
GetMembers() | MemberInfo[] | 해당 형식의 멤버 목록 반환 |
GetMethods() | MethodInfo[] | 해당 형식의 메소드 목록 반환 |
GetNestedTypes() | Type[] | 해당 형식의 내장 형식 목록 반환 |
GetProperties() | PropertyInfo[] | 해당 형식의 프로퍼티 목록 반환 |
검색 옵션
GetFields()나 GetMethods() 같은 메소드는 검색 옵션을 지정할 수 있다.
System.Reflection.BindingFlags 열거형을 통해 검색 옵션 구성
p. 556 ~ 560
리플렉션을 이용해 특정 형식의 인스턴스를 만들고 데이터를 할당하며 메소드를 호출할 수 있다.
인스턴스 생성
System.Activator 클래스 필요
Activator.CreateInstance() 메소드는 매개변수로 입력받은 형식의 인스턴스를 생성 / 반환한다.
object a = Activator.CreateInstance(typeof(int));
일반화 지원
List<int> list = Activator.CreateInstance<List<int>>();
프로퍼티 할당
Type.GetProperty() 메소드
매개변수로 받는 이름의 프로퍼티를 찾아 그 이름의 PropertyInfo 객체 반환
PropertyInfo 클래스
SetValue() 메소드
프로퍼티에 값 할당
GetValue() 메소드
프로퍼티의 값 조회
메소드 호출
MethodInfo 클래스
동적 인스턴스 생성 / 프로퍼티 할당 / 메소드 호출 예시 코드
p. 560 ~ 565
프로그램 실행 중(런타임)에 새로운 형식을 만들어낼 수 있다.
System.Reflection.Emit 네임스페이스
주요 클래스
클래스 | 설명 |
---|---|
AssemblyBuilder | 동적 어셈블리를 정의하고 나타낸다. |
ConstructorBuilder | 동적으로 만든 클래스의 생성자를 정의하고 나타낸다. |
CustomAttributeBuilder | 사용자 정의 애트리뷰트를 만든다. |
EnumBuilder | 열거 형식을 정의하고 나타낸다. |
EventBuilder | 클래스의 이벤트를 정의하고 나타낸다. |
FieldBuilder | 필드를 정의하고 나타낸다. |
GenericTypeParameterBuilder | 동적으로 정의된 형식(클래스)과 메소드를 위한 일반화 형식 매개변수를 정의하고 생성한다. |
ILGenerator | MSIL(Microsoft Intermediate Language) 명령어를 생성한다. |
LocalBuilder | 메소드나 생성자 내의 지역 변수를 나타낸다. |
MethodBuilder | 동적으로 만든 클래스의 메소드, 또는 생성자를 정의하고 나타낸다. |
ModuleBuilder | 동적 어셈블리 내의 모듈을 정의하고 나타낸다. |
OpCodes | ILGenerator 클래스의 멤버를 이용한 내보내기 작업에 사용할 MSIL 명령어의 필드 표현을 제공한다. |
ParameterBuilder | 매개변수 정보를 생성하거나 결합시킨다. |
PropertyBuilder | 형식(클래스)의 프로퍼티를 정의한다. |
TypeBuilder | 실행 중에 클래스를 정의하고 생성한다. |
클래스 사용 요령
AssemblyBuilder를 이용해 어셈블리를 만든다.
ModuleBuilder를 이용해 어셈블리 안에 모듈을 만들어 넣는다.
모듈 안에 TypeBuilder로 클래스(형식)를 만들어 넣는다.
클래스 안에 메소드(MethodBuilder 이용)나 프로퍼티(PropertyBuilder 이용)를 만들어 넣는다.
4에서 생성한 것이 메소드라면, ILGenerator를 이용해 메소드 안에 CPU가 실행할 IL 명령들을 넣는다.
형식 내보내기 예시코드 p. 565 ~ 566
p. 566 ~ 577
코드에 대한 부가 정보를 기록하고 읽을 수 있는 기능
주석과 애트리뷰트의 차이점
주석
사람이 읽고 쓰는 정보
애트리뷰트
사람이 작성하고 컴퓨터가 읽는 정보
사용
[ 애트리뷰트_이름( 애트리뷰트_매개변수 ) ]
클래스, 구조체, 메소드, 프로퍼티 등
호출자 정보 애트리뷰트
애트리뷰트 | 설명 |
---|---|
CallerMemberNameAttribute | 현재 메소드를 호출한 메소드 또는 프로퍼티의 이름을 나타낸다. |
CallerFilePathAttribute | 현재 메소드가 호출된 소스파일의 경로를 나타낸다. 이때 경로는 소스 코드를 컴파일할 때의 전체 경로를 나타낸다. |
CallerLineNumberAttribute | 현재 메소드가 호출된 소스 파일 내의 행( Line) 번호를 나타낸다. |
예시 코드 p. 571
using System;
using System.Runtime.CompilerServices;
namespace CallerInfo
{
public static class Trace
{
public static void WriteLine(string message,
[CallerFilePath] string file = "",
[CallerLineNumber] int line = 0,
[CallerMemeberName] string member = "")
{
Console.WriteLine(
$"{file}(Line:{line}) {member}: {message}");
}
}
class MainApp
{
static void Main(string[] args)
{
Trace.WriteLine("즐거운 프로그래밍!");
}
}
}
// 결과 (예시 파일 경로)
C:\이것이 C#이다\CallerInfo\MainApp.cs(Line:22) Main: 즐거운 프로그래밍!
p. 571 ~ 577
애트리뷰트 또한 클래스
System.Attribute 클래스를 상속 받아 생성
class History : System.Attribute
{
//
}
사용자 지정 애트리뷰트는 디폴트로 단 한 번만 사용 가능
⇒ System.AttributeUsage 라는 애트리뷰트를 활용해 해결 가능
System.AttributeUsage
애트리뷰트의 애트리뷰트
설명할 대상 / 중복 사용 가능 여부 등을 부가 설명
애트리뷰트 선언부에 사용
[System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple=true)]
class History : System.Attribute
{
//
}
Attribute Target
첫 번째 매개변수
설명 대상 명시
표 : 생략 p. 575
논리합 연산자( | ) 사용 가능
AllowMultiple
두 번째 매개변수
중복 사용 가능 여부 명시