유니티에서 리플렉션은 프로그램 실행중에 자신의 구조를 가져오거나 수정할 수 있는 기능이다. 컴파일 타임에 객체를 조작하는것이 아닌 프로그램 실행중에 정보를 얻을 수 있으며 이를 사용하여 동적 로딩, 일반화, 메소드 호출 등 다양한 작업을 수행할 수 있다.
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using Unity.VisualScripting;
using UnityEngine;
public class ReflectionExample : MonoBehaviour
{
private int exampleInt = 10;
public int exampleInt2 = 20;
// Start is called before the first frame update
void Start()
{
System.Type myType = typeof(ReflectionExample);
System.Type myType2=this.GetType();
Debug.Log($"myType.Name : {myType.Name}");
Debug.Log($"myType2.Name : {myType2.Name}");
//public 멤버 함수를 가져와서 호출한다
MethodInfo exampleFunctionMethodInfo = myType.GetMethod("ExampleFunction");
exampleFunctionMethodInfo?.Invoke(this, null);
// non public(private or protected) 함수를 가져와서 호출한다.
MethodInfo exampleFunction2MethodInfo = myType.GetMethod("ExampleFunction2", BindingFlags.NonPublic | BindingFlags.Instance);
exampleFunction2MethodInfo?.Invoke(this, null);
//non public 멤버 변수를 가져온다.
FieldInfo exampleIntInfo = myType.GetField("exampleInt", BindingFlags.NonPublic | BindingFlags.Instance);
exampleIntInfo?.SetValue(this, 50);
Debug.Log($"example int value : {exampleIntInfo?.GetValue(this)}");
Debug.Log($"example int value real member : {exampleInt}");
// public 멤버 변수를 가져온다.
FieldInfo exampleIntInfo2 = myType.GetField("exampleInt2");
Debug.Log($"example in2t value : {exampleIntInfo?.GetValue(this)}");
}
// Update is called once per frame
void Update()
{
}
public void ExampleFunction()
{
Debug.Log("Called ExampleFunction");
}
void ExampleFunction2()
{
Debug.Log("Called ExampleFunction2");
}
public void ExampleFunction3()
{
Debug.Log("Called ExampleFunction3");
}
}
리플렉션을 사용하여 클래스의 메서드와 필드에 접근하고 값을 변경하고 호출하는 방법이다. typeof 연산자나 GetType() 메서드를 사용하여 객체의 Type을 얻는다. GetMethod() 메서드를 사용하여 메서드를 가져온 후 Invoke() 메서드로 호출한다. BindingFlags를 사용하여 private 메서드도 호출할 수 있다. GetField() 메서드를 사용하여 필드를 가져온 후 SetValue()와 GetValue()로 값을 변경하거나 조회한다.
둘다 리플렉션을 통해 설정된 50이 출력된다.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
public class ReflectionClass
{
public ReflectionClass()
{
Debug.Log("Created ReflectionClass");
}
public ReflectionClass(int a, int b)
{
Debug.Log($"Created ReflectionClass with member values : a : {a} b : {b} ");
}
}
public class ReflectionExampleFriend : MonoBehaviour
{
ReflectionExample _cachedExample;
// Start is called before the first frame update
void Start()
{
MethodInfo method = typeof(GameObject).GetMethod("GetComponent", new System.Type[] { typeof(System.Type) });
_cachedExample = method?.Invoke(gameObject, new object[] { typeof(ReflectionExample) }) as ReflectionExample;
_cachedExample.ExampleFunction3();
ReflectionClass instance = Activator.CreateInstance(System.Type.GetType("ReflectionClass")) as ReflectionClass;
ReflectionClass instance2 = Activator.CreateInstance(System.Type.GetType("ReflectionClass"), new object[] { 1, 2 }) as ReflectionClass;
}
// Update is called once per frame
void Update()
{
}
}
typeof(GameObject).GetMethod("GetComponent")를 사용하여 GameObject의 GetComponent 메서드를 가져와 Reflection을 통해 호출한다. 이를 통해 ReflectionExample 타입의 인스턴스를 얻는다.
Activator.CreateInstance()를 사용하여 Reflection을 통해 클래스를 생성한다. 생성자의 매개변수를 전달하여 다양한 생성자를 호출할 수 있다.
ExampleFunction3 메서드 출력값과 매개변수 없는 인스턴스 생성자와 매개변수 전달하여 생성된 생성자가 호출된다.
리플렉션은 유연성과 동적 프로그래밍 기능을 제공하지만, 성능 저하와 코드의 가독성 및 유지보수성에 일정한 제약이 따른다. 따라서 사용 시 성능과 관리적인 측면을 고려하여 적절히 활용하는 것이 중요다. 주로 런타임에 동적인 작업이 필요한 경우나 메타프로그래밍 기법을 구현할 때 리플렉션을 활용할 수 있다.
'개인 공부 > C#' 카테고리의 다른 글
델리게이트(delegate)와 이벤트 (event) (1) | 2024.07.26 |
---|---|
추상 클래스 (0) | 2024.07.26 |
튜플 (0) | 2024.07.25 |
LINQ (Language Integrated Query) (0) | 2024.07.12 |
파일 입출력 (0) | 2024.07.12 |