Game !

[UE] 리플렉션2022. 4. 30. 01:13

 


리플렉션

프로그램이 실행시간(런타임)에 자기 자신을 조사하는 기능
▶ 자기자신의 정보를 들여다본다.

 

 

 

① 런타임

우리가 코드를 짜고 빌드를 하게되면 컴파일을 하게 되는데
컴파일의 순서는 아래와 같다.

 

번역된 어셈블리는 우리가 미리 작성한 스크립트(소스파일) 기준으로 생성이 된다.

런타임 때( = 어셈블리가 동작할 때 )는 메서드가 호출되거나 필드의 값을 변경하는 것들이 모두 프로그래머가 빌드하기 전에 스크립트로 미리 작성해놓은 대로 실행된다.

즉, 런타임 때 동작하는 것들은 스크립트에 정의해놓은 일련의 작업일 뿐이다.

 

--> ex. ( C++ 스타일 ) 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 
 
switch( selectType )
{
    case 1:
        {
            cout << " A 값을 " + object.a + " 값으로 변경했습니다." <<endl;
        }
        break;
    case 2:
        {
            cout << " B 값을 " + object.b + " 값으로 변경했습니다." <<endl;
        }
        break;
    case 3:
        {
            cout << " C 값을 " + object.c + " 값으로 변경했습니다." <<endl;
        }
        break;
}
 
 
 
cs

 

> 이 코드는 단순히 이미 알고있는, 미리 정의된 동작만 수행한다.

(case 1, 2, 3 ---> 케이스가 추가되면 상황에 따라 프로그래머가 작성해야한다.)

 

 

 

하지만!! 리플렉션을 사용하게 되면 형식(Type)에 정의된 필드나 메서드를 조사해서 값을 가져오거나 설정하거나 호출할 수 있게된다.

즉, 위의 예제처럼 일일히 하나씩 미리 구현할 필요가 없어진다.

 

--> ex. ( C# 스타일 - 리플렉션 코드 )

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 
 
// GetType() : 오브젝트의 형식(Type)을 가져온다.
// GetField() : 형식(Type) 내의 필드 정보를 조사한다.
// Where((i) => i.FieldType == typeof(int)) : int 즉, 정수 형식 필드만 사용하겠다.
var _getField = myObject.GetType()
                        .GetField( BindingFlags.Instance | BindingFlags.Public )
                        .Where( (i) => i.FieldType == typeof(int) )
                        .ToArray();
 
// Console.ReadLine() : C# 에서 콘솔 입력 받는 표준 문법
int _userInputValue = Console.ReadLine();
 
if ( selectType >= 1 && selectType <= _getField.Length )
{
    _getField[selectType - 1].SetValue(object, _userInputValue);
    
    Log.Debug(" {0} 값을 {1} 값으로 변경했습니다. ", _getField[selectType - 1], _userInputValue);
}
 
 
// 런타임 때 
// GetType()     예제로         정보를 가져와서
// GetField()     예제로         정보를 알아내서
// SetValue()     예제로         적절히 맞춰서 사용
 
 
cs

 

 

 

위의 예제를 참조하면

런타임 때 코드가 직접 정보를 알아내서(알 수 있어서) 적절히 맞춰서 사용할 수 있다.

▶ 리플렉션

 

 

 

② 리플렉션의 장점

 

위의 예제에서 Class에 필드가 추가되거나 제거되거나 수정이 되어도

코드 부분은 이를 반영하여 결과를 유동적으로 표시할 수 있다는 것.

 

 

 

 


언리얼의 리플렉션

1.
에디터의 디테일 패널, 시리얼라이제이션, 가비지 콜렉션, 네트워크 리플리케이션, 블루프린트와 C++의 커뮤니케이션 등 다수의 시스템에 탑재되어 있다.

리플렉션은 JAVA, C# 에서는 기본적으로 제공하는 기능이지만 C++ 에서는 제공하지 않아서 언리얼에서 자체적으로 제공하며 C++ 클래스, 구조체, 함수 멤버변수, 열거형... 등 관련 정보를 수집/질의/조작하는 별도의 시스템이 구축되어 있다.
---> 이것을 언리얼 프로퍼티 시스템 이라고도 부르며, 매크로 함수 형태로 되어있다.


cf.
에디터의 디테일 패널 :
언리얼 에디터도 일종의 언리얼 어플리케이션이다. 그래서 리플렉션을 통해 에디터가 켜져있는 중에도 컴파일이 끝나면 디테일 패널이 갱신된다. 


2. 
리플렉션 기능이 적용됐으면하는 유형이나 프로퍼티에 특수한 주석을 달아주면 Unreal Hear Tool ( UHT )이 그 프로젝트를 컴파일 할 때 해당 정보를 수집한다.
단, 리플렉션이 있는 유형으로 처리하려면 헤더에 특수한 include 를 해주어야 한다.
---> #include "FileName.generated.h"

* 특수한 주석 :
UCLASS( ), USTRUCT( ), UENUM( ), EFUNCTION( ), UPROPERTY( ) ....
---> 이 매크로 각각은 유형 및 멤버 선언 전에 오며, 추가적인 키워드를 담을 수 있다. (EditAnywhere 등)



----------------------------
★ 주의할 점 !!
UCLASS( )
class A:
private:
     int8 MyTeamCount;

리플렉션 클래스에 네이티브 변수를 넣을 수도 있다.
단, 리플렉션된 프로퍼티가 아닌 변수는 리플렉션된 값을 그대로 저장할 경우 ( 예를 들어, UObject* 와 같은 )
가비지 콜렉터가 레퍼런스를 확인할 수 없기에 조심해야한다.

 

 

 

출처:

https://kyoun.tistory.com/126

https://cs-solution.tistory.com/20?category=1046133