카테고리 없음

🌟 C#의 null과 Unity의 null😋 🌟

minsoungdev 2026. 8. 4. 20:27

안녕하세요. 박민성입니다. 🤗

 

오늘은 C#의 null과 Unity의 null 차이에 대해서 글을 쓰고자 합니다. 🤔

null 관련해서 찾아보기도 하고 예전에 null 병합 연산자나 할당 연산자를 찾아보다가 여기까지 보게 되었습니다.

null 연산자에 대해서 글을 쓰려고 했으나 제가 이미 null 관련 연산자에 대해서 잘 정리된 글을 봐서 너무 그 글과 비슷해질까봐

#의 null과 Unity의 null 차이에 관해서 쓰려고 합니다.

 

1. 일반 C#에서 null이란?

일반 C#에서 null은 변수가 참조하는 객체가 없다는 뜻입니다.

Player player = null;

if (player == null)
{
    Debug.Log("참조하는 객체가 없음");
}

참조형 변수는 객체의 실제 데이터를 직접 담는 게 아니라 객체를 가리키는 참조를 저장하는 것입니다.

일반 C#에서 null은 참조 변수가 실제 객체를 가리키고 있지 않은 상태를 의미합니다.

 

2. Unity 오브젝트의 이중 구조

GameObject, MonoBehaviour, Component, ScriptableObject 같은 Unity 객체는 모두 UnityEngine.Object를 상속합니다.

F12를 통해서 타고 타고 올라가서 확인하실 수 있습니다.

 

이런 객체는 단순한 C# 객체 하나로만 구성되지 않습니다.

개념적으로 C#에서 관리되는 객체와 Unity 엔진의 네이티브 객체는 다른 것인 겁니다.

 

3. Destroy() 이후에는 어떻게 될까요~?

Destroy(target);

 

Destroy()는 Unity 오브젝트의 제거를 요청합니다.

 

실제 제거는 보통 현재 프레임의 적절한 시점에 처리됩니다.

private void CheckDestroyedObject()
{
    GameObject target = new GameObject("Target");

    Destroy(target);

    Debug.Log(target == null);
}

네이티브 객체가 파괴된 뒤에도 C# 쪽의 관리 객체 참조가 잠시 남아 있을 수 있습니다. 하지만 파괴 후에는 unity는 null처럼 처리하게 됩니다.

 

4. 어떻게 파괴된 오브젝트가 null처럼 보일까요~?

Unity는 UnityEngine.Object의 == 연산자를 직접 구현해 놓았습니다.

일반적인 C# 참조 비교만 하는 게 아니라 연결된 Unity 네이티브 객체가 살아 있는지도 확인합니다.

if (target == null)
{
    Debug.Log("대상이 없거나 파괴됨");
}

두 경우를 모두 true로 처리할 수 있습니다.

1. C# 참조 자체가 진짜 null

2. C# 관리 객체는 남아 있지만 Unity 네이티브 객체가 파괴된 상태

그래서 Unity의 파괴된 객체를 흔히 가짜 null, Unity null, fake null 같은 표현으로 설명되어 있습니다.

 

Unity의 == null 검사는 C# 참조가 실제로 null인지뿐만 아니라 연결된 Unity 네이티브 객체가 파괴되었는지도 확인합니다.

Unity 문서에서 MonoBehaviour나 ScriptableObject를 null과 비교하면 관리 객체가 남아 있어도 true가 반환될 수 있다고 설명합니다.

 

5. == null과 ReferenceEquals()의 차이

Debug.Log(target == null);

UnityEngine.Object에 구현된 == 연산자가 호출됩니다.

그래서 네이티브 객체가 파괴되었다면 true가 나옵니다.

 

실제 C# 참조 검사에서는

Debug.Log(ReferenceEquals(target, null));

ReferenceEquals()는 == 연산자 오버로딩을 사용하지 않습니다.

그렇기에 오직 C# 관리 객체의 참조 자체가 진짜 null인지 확인하게 되는데여

Debug.Log(target == null);                  // true
Debug.Log(ReferenceEquals(target, null));   // false

때문에 파괴된 Unity 오브젝트에서는 개념적으로 다음과 같은 결과가 나올 수도 있습니다.

target == null은 Unity 네이티브 객체가 파괴되었는가?

ReferenceEquals(target, null)은 C# 관리 객체의 참조 자체가 진짜 null인가? 를 확인하게 됩니다.

 

6. ?.와 ?? 사용 시 주의점

player?.Attack();

player가 null이 아니면 Attack()을 실행한다는 뜻입니다.

 

하지만 Unity 오브젝트에서는 주의해야 합니다.

target?.SetActive(false);

?.는 Unity가 오버로드한 == 연산자를 통해 파괴 여부를 검사하지 않습니다. C# 관리 참조가 실제 null인지 확인하기 때문에 관리 객체는 남고 네이티브 객체만 파괴된 Unity 오브젝트를 제대로 걸러내지 못할 수 있습니다.

GameObject result = target ?? fallback;

??도 같은 문제가 있습니다.

 

Unity 공식 API 문서도 UnityEngine.Object에는 ?.와 ??를 이용한 Unity식 null 검사가 지원되지 않는다고 명시해 있습니다.

?.와 ??는 Unity가 오버로드한 == null 검사를 사용하지 않으므로 파괴된 Unity 오브젝트를 확인할 때 주의를 해야 합니다.

 

8. 파괴된 객체에 접근하면 어떻게 될까요?

파괴된 Unity 오브젝트는 null처럼 비교되지만 변수에 대한 C# 참조가 남아 보일 수 있습니다.

Destroy(target);

yield return null;

target.SetActive(false);

이 상태에서 Unity 쪽 멤버에 접근하면 오류가 발생할 수 있습니다.

때문에

Destroy()한 객체는 이후 다시 사용하지 않는 게 기본입니다.

 

필요하다면~! 코드상 참조도 직접 비울 수 있습니다.

Destroy(target);
target = null;

Destroy()가 처리되는 시점을 앞당기는 것은 아닙니다. 단지 현재 변수가 더 이상 그 관리 객체를 가리키지 않도록 만드는 것입니다.

 

정리하자면

Unity 오브젝트는 C# 관리 객체와 네이티브 객체가 연결된 구조입니다.

Destroy()는 Unity 네이티브 객체를 파괴하는 것이고  관리 객체의 참조는 남아 있을 수 있습니다.

Unity는 == 연산자를 구현해 파괴된 객체도 null처럼 판단하지만 ReferenceEquals()는 실제 C# 참조만 검사합니다.

?.와 ??는 파괴된 Unity 오브젝트를 제대로 판별하지 못할 수 있습니다.

 

이상으로 C#의 null과 Unity의 null에 대해서 알아보았는데여

처음에는 이해도 잘안되고.... 흠... 뭔가뭔지도 모르겠고.... 흠... 하다가

어느 정도....? 흐름 정도는...? 이해한 것 같습니다. 설명이 안되었을 수도 잇지만...

그래도 열심히 써보았습니다.

 

오늘의 노래 추천은 

김상민 - You라는 노래입니다.

특히 하이라이트에서 목을 긁는 것이 참 좋았습니다.

 

내일은 더욱 알차게 보내고 작성해 보도록 하겠습니다. 

봐주셔서 감사합니다. ☺️