[C#] Nullable을 활용한 효율적이고 안전한 개발
최근에 Android SDK 버전 지원 문제로 프로젝트의 Unity 버전을 업그레이드 하였다.
(예로 2020.1 버전은 API level 30까지만 지원, 2022.3 버전은 현재 API level 35까지 지원 중)
그러면서 C# 버전 관련해서도 테스트를 하며 잠시 변경이 있었는데, nullable을 활용해서 조금 더 효율적이고 안전하게 개발할 수 있는 방법이 있는 듯 하여 정리해보기로 했다.

개발을 하다보면 필연적으로, 자주 만나게 되는 오류가 있는데 바로 NullReferenceException이다.

line 14와 line 27을 확인해보면, Test2함수를 실행할 때 null을 넘겨줬는데 내부에서 null 체크를 하지 않고 classA라는 객체에 접근했기 때문에 NullReferenceException이 발생한 것이다.
Test 함수에서는 classA가 null이 아닌 경우에만 classA에 접근했기 때문에 이런 문제가 발생하지 않는다.
코드를 읽어보면 NullReferenceException이 발생할 수 있다는 것을 알 수 있지만, 컴파일러가 경고를 표시해주지는 않고 있다. 때문에 실수가 발생할 여지가 있다.
개발 규모가 작다면 null을 다루는 것이 크게 어렵지 않을 수 있다. 어떤 객체가 null일지 아닌지 알기가 쉬우니까. 그러나 개발 규모가 커지고, 개발에 참여하는 인원이 많아지면 본인이 아닌 다른 사람들이 작업한 코드를 활용할 일이 많아지고, 이 경우 null 관련해서 문제가 발생할 가능성이 높아진다.
예로 몬스터의 이름을 알고 싶은데, Monster.GetName()이라는 Method가 있어서 사용했다고 치자.
monster가 null이 아니라는 걸 체크하고 사용해서 NullReferenceException이 발생하지 않을 줄 알았는데, 다른 개발자가 Monster가 죽을 때 이름이 필요없어질 거라고 생각하고 이때 name에 null을 할당해버린 사실을 몰랐다면 NullReferenceException이 발생할 수 있다.
위는 단순한 예이고, 개발을 하면서 이와 같이 null 체크와 관련해서 내적 갈등이 생기는 경우가 꽤 있다.
여기서 null 체크를 해야 하는가? 하지 않아도 되는가? 와 같은 갈등이다.
null이 올 수 있거나, 혹여나 null이 와서 크리티컬한 문제가 발생할 수 있다면 당연히 null 체크를 해줘야 하지만, 구조상 null이 오면 안 되는 곳도 있기 때문에 이런 곳에서까지 null 체크를 해줘야 하는가? 와 같은 생각을 하곤 한다.
C# 8.0부터 제공하는 Nullable 기능을 사용하면 이런 고민을 크게 줄일 수 있다.

(블루 아카이브의 자동 제조 기능이 다소 아쉬운 점이 있어서 테이블 읽기도 직접 구현해보고, 자동 제조를 내가 만든다면 어떻게 만들었을까 싶어서 해보면 재밌겠다는 생각 중이다)
위와 같이 프로젝트 루트 폴더에 Directory.Build.props 라는 파일을 만들고
<Project>
<PropertyGroup>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
내용을 위와 같이 채워넣으면 Nullable 기능을 활용할 수 있다.

이러면 스크립트에서 아까와는 다르게 노란색 경고 표시가 나타난다.


경고를 살펴보면 위와 같다.
위는 nullable로 지정되어 있지 않은데 null을 사용해서 경고를 표시하는 것이고,
아래는 nullable로 지정되어 있지 않은데 null 체크를 하려고 해서 경고를 표시하는 것이다.

Test 코드는 매개변수 타입을 ClassA -> ClassA? 로 수정하여 ClassA가 null일 수 있다는 것을 명시적으로 표시하여 경고가 사라졌다.

이로 인해 Test 함수의 경고가 사라졌는데, Test2의 경우도 매개변수가 null일 수 있다는 것을 명시적으로 표시하였지만 이 경우 내부에서 null체크 없이 classA에 접근하려고 하면 null일 수 있다는 경고를 표시한다.

위와 같이
<WarningsAsErrors>Nullable</WarningsAsErrors>
를 사용하면 Nullable 경고를 컴파일 에러로 변경할 수 있다.

그러면 위와 같이 nullable 객체에 대해서 null 검사를 하지 않으면 컴파일 에러가 나타나게 된다.
현재 참여 중인 프로젝트에서는 이미 개발이 많이 진행되어 변경할 사항이 많아서 도입하긴 어렵겠지만, 나중에 개발을 시작할 때 Nullable을 사용하도록 하면 개발할 때 좋을 것 같다.