Reflection
필요 네임스페이스
1
2
using System;
using System.Reflection;
특정 클래스 타입 가져오기
1
Type targetType = Type.GetType("클래스명");
특정 네임스페이스 내에 있는 클래스 타입 가져오기
1
Type targetType = Type.GetType("네임스페이스명.클래스명");
특정 네임스페이스의 모든 클래스 타입 가져오기(모든 어셈블리 확인)
1
2
3
4
5
6
7
8
string asmName = "UnityEngine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null";
string nsName = "UnityEngine";
var classTypes =
AppDomain.CurrentDomain.GetAssemblies() // 모든 어셈블리 대상
.Where(asm => asm.FullName == asmName) // 특정 어셈블리(exe, dll)로 필터링
.SelectMany(asm => asm.GetTypes()) // 모든 타입들 가져오기
.Where(t => t.IsClass && t.Namespace == nsName); // 클래스타입 && 특정 네임스페이스로 필터링
현재 어셈블리의 모든 클래스 타입 가져오기
1
2
3
var classTypes =
Assembly.GetExecutingAssembly().GetTypes()
.Where(t => t.IsClass /*&& t.Namespace == nsName*/);
프로그램 내 모든 어셈블리에서 특정 타입 가져오기
1
2
3
4
5
6
7
8
Type type =
AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(ass => ass.GetTypes())
.Where(t => t.Name == "TargetType")
.FirstOrDefault();
// 해당 타입이 아예 없는데 .First()를 호출하면 예외가 발생하므로,
// FirstOrDefault()를 호출하는 것이 안전하다.
다른 어셈블리(예: DLL) 내에 있는 클래스 타입 가져오기
1
2
3
4
5
6
7
8
9
10
11
Type targetType = Type.GetType("네임스페이스명.클래스명, 어셈블리명");
// 어셈블리명 예시
string shortName = "UnityEngine";
string fullName = "UnityEngine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null";
// 실제 예시 - shortName 이용
Type.GetType("UnityEngine.Rigidbody, UnityEngine");
// 실제 예시 - fullName 이용
Type.GetType("UnityEngine.Rigidbody, UnityEngine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null");
알고 있는 타입의 동일 어셈블리 내의 특정 클래스 가져오기
- 아주 유용함
1
2
3
Type knownType = ...; // 알고 있는 타입
Type goal = knownType.Assembly.GetType("네임스페이스명.클래스명");
타입으로 객체 생성하기
1
object instance = Activator.CreateInstance(targetType);
특정 클래스의 메소드 가져오기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
MethodInfo targetMethod = targetType.GetMethod (
"메소드명",
new Type[] { typeof(파라미터1타입), typeof(파라미터2타입) }
);
// Binding Flag를 지정해야 하는 경우
targetType.GetMethod
(
"메소드명",
BindingFlags.~~,
null, // Binder -> null로 둔다.
new Type[] { ~~ },
null, // ParameterModifier[] -> null로 둔다.
);
가져온 메소드 호출하기
1
2
3
4
5
6
7
8
// 1. 정적 메소드가 아니고, 매개변수가 존재하는 경우
targetMethod.Invoke(instance, new object[]{ 파라미터1, 파라미터2 });
// 2. 정적 메소드가 아니고, 매개변수가 0개인 경우
targetMethod.Invoke(instance, null);
// 3. 정적 메소드이고, 매개변수가 0개인 경우
targetMethod.Invoke(null, null);
제네릭 메소드에 원하는 타입 넣어서 호출하기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private class TargetClass
{
public void GMethod<T>()
{
Console.WriteLine($"Generic Method Call : {default(T)}");
}
}
public static void Run()
{
Type type = typeof(TargetClass);
// 제네릭 메소드의 T에 int 타입 넣어서 메소드 정보 가져오기
MethodInfo method = type.GetMethod("GMethod").MakeGenericMethod(new Type[] { typeof(int) });
object instance = Activator.CreateInstance(type);
method.Invoke(instance, null);
}
필드의 값 가져오기
-
필드의 값을 가져오려면
FieldInfo
가 필요하다. -
대상 필드가 동적일 경우
GetValue(object)
의 인수로 객체가 필요하며,
정적일 경우 객체가 필요하지 않다. (GetValue(null)
)
1
2
3
4
5
public class TestClass
{
private float value = 4f;
private static float staticValue = 5f;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
TestClass tc = new TestClass();
Type t = tc.GetType();
// 1. 동적 필드의 값 가져오기
BindingFlags bf1 = BindingFlags.NonPublic | BindingFlags.Instance;
FieldInfo fi1 = t.GetField("value", bf1);
float value1 = (float)fi1.GetValue(tc);
// 2. 정적 필드의 값 가져오기
BindingFlags bf2 = BindingFlags.NonPublic | BindingFlags.Static;
FieldInfo fi2 = t.GetField("staticValue", bf2);
float value2 = (float)fi2.GetValue(null);
인터페이스 타입으로 구현 타입들 가져오기
1
2
3
interface IPoo { }
class Some1 : IPoo { }
class Some2 : IPoo { }
이런 인터페이스 구현 관계가 있을 경우,
IPoo
의 타입을 통해 Some1
, Some2
를 찾을 수 있다.
1
2
3
4
5
6
Type targetType = typeof(IPoo);
var types =
Assembly.GetAssembly(targetType).GetTypes()
.Where(t => !(t.GetInterface(targetType.Name) is null))
.ToArray();