묵시적 형 변환
C,C++에서는 어떤 변수가 NULL인지 아닌지 검사하기위해 아래와 같은 조건문을 쓸 수 있다.
Asdf* asdf = new Asdf;
if (asdf) {
// do sth
}
delete asdf;
이 동네에선 조건문 안에 있는 수식을 평가해서 나온 값이 0이면 FALSE
, 그게 아니면 TRUE
로 판단하기 때문이다.
Java나 C#같은 고오급 언어에선 다르다. if 조건문 안에 bool 타입의 수식이 들어가야 한다. 그냥 C,C++에서 하던대로 쿨하게 if 조건 안에 변수 하나만 명시하는건 그 변수가 bool 타입이 아닌 이상 불가능하다.
Asdf asdf = new Asdf();
if (asdf == null)
{
// do sth
}
if (asdf)
{
// error: Cannot implicitly convert type 'Asdf' to 'bool'
}
하지만 유니티에선 이게 가능하다. 물론 다 되는건 아니고 정확히는 유니티 엔진의 Object
를 상속받는 클래스의 인스턴스들만 가능하다. (object
아님!) MonoBehaviour
나 Component
같이 Object
를 상속받는 클래스들도 당연히 가능.
GameObject asdf;
if (asdf)
{
// do sth
}
왜 가능하냐면 유니티의 Object
클래스가 bool
타입에 대해서 묵시적 형 변환 연산자를 구현해 놨기 때문.
// UnityEngine/Object.cs
public static implicit operator bool(Object exists)
{
return !Object.CompareBaseObjects(exists, null);
}
private static bool CompareBaseObjects(Object lhs, Object rhs)
{
bool flag = lhs == null;
bool flag2 = rhs == null;
bool result;
if (flag2 && flag)
{
result = true;
}
else if (flag2)
{
result = !Object.IsNativeObjectAlive(lhs);
}
else if (flag)
{
result = !Object.IsNativeObjectAlive(rhs);
}
else
{
result = (lhs.m_InstanceID == rhs.m_InstanceID);
}
return result;
}
private static bool IsNativeObjectAlive(Object o)
{
return o.GetCachedPtr() != IntPtr.Zero || (!(o is MonoBehaviour) && !(o is ScriptableObject) && Object.DoesObjectWithInstanceIDExist(o.GetInstanceID()));
}
Object null 체크
저게 왜 되는건지 찾아보다가 유니티의 null체크 방식들과 그 성능을 비교한 아티클을 우연히 먼저 찾았는데, 여기서 말하길 대부분의 유니티 사용자가 제일 많이 사용하는 (아마) null 체크 방식인 ‘GameObject
타입과 null 타입을 비교하는것’ 이 제일 느리고, ‘게임 오브젝트를 object
형으로 다운 캐스팅 시키고 null과 비교하는 것’ 이 제일 빠른 성능을 보여준다는 결과를 보게 되었다.
GameObject obj;
if (obj == null)
{
// slowest
}
if ((object)obj == null)
{
// fastest
}
처음에 봤을땐 ‘null
을 GameObject
타입으로 승격시키는데 시간이 걸리나?’ 했는데, 위의 Object.cs의 코드를 보면 CompareBaseObjects()
안에서 내부 변수들이 진짜로 살아있는지 이것저것 더 살펴본다. 여기에서 시간이 더 들어가는것일듯. 게임 오브젝트를 object
로 강제 캐스팅해서 비교하는 로직에선 위의 각종 검사 루틴을 거치지 않고, 그냥 C# 레퍼런스가 null인지 아닌지 여부만 검사하고 끝내니까 더 빠를테고.
obj
가 진짜로 null
을 가리키는 레퍼런스 일 때도 true
를 반환하게 하는것에 더해서, Destroy(obj)
등으로 C++ 쪽 객체가 파괴되는경우 C#쪽 레퍼런스는 null
이 아니라 무엇인가를 가리키고 있는 상태이지만, 실제로는 가리키는것이 파괴된(될) 객체인 경우에도 null체크에서 true
를 반환하게 하기 위해서 이렇게 추가 로직을 더 구현 해 놓은듯 하다.
더 알아보고 싶으면 유니티 블로그의 아티클참조.
References
- https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/implicit
- https://github.com/MattRix/UnityDecompiled/blob/82e03c823811032fd970ffc9a75246e95c626502/UnityEngine/UnityEngine/Object.cs
- http://bonusdisc.com/null-references-in-unity/
- https://blogs.unity3d.com/kr/2014/05/16/custom-operator-should-we-keep-it/
'Note' 카테고리의 다른 글
TIL: C#에서 enum이나 struct를 Dictionary의 Key값으로 사용하면 쓰레기가 생긴다 (1) | 2017.07.06 |
---|---|
TIL: docker 컨테이너안에서 ip 바인딩은 localhost가 아니라 0.0.0.0으로 해야한다 (0) | 2017.07.02 |
TIL: git --fixup, --autosquash (0) | 2017.06.23 |
TIL: git fetch가 실제로 원격에서 데이터를 받아온다 (0) | 2017.06.04 |
TIL: 윈도우에서 ALT+<아스키 번호> 조합으로 문자를 입력할 수 있다 (0) | 2017.05.31 |