명시적 Nullable선언

안녕하세요.

C# 8.0 이상에서 프로젝트 차원의 C# null 허용 컨텍스트를 지정하는 속성이 새로 추가되었는데요.
아래와 같은 내용을 링크에서 확인하였습니다.

  • 명시적 형식의 참조 변수는 모두 null을 허용하지 않는 참조 형식으로 해석됩니다.
  • 제네릭의 class 제약 조건의 의미가 null을 허용하지 않는 참조 형식을 의미하도록 변경되었습니다.
  • 이러한 새 규칙으로 인해 새로운 경고가 생성됩니다.

여기서 궁금한 점은 nullable을 왜 명시적으로 선언하게끔 변경되었는가? 입니다.
프로젝트 빌드를 할 경우 에러는 발생하지 않지만 경고로 null이 아닌값을 포함해야합니다. 속성을(를) null 허용으로 선언해 보세요. 라는 메세지가 뜨고 있어 괜히 거슬리네요.

문서대로 프로젝트에서 disable같이 속성값을 변경하면 해결되는 문제이긴 하지만 MS에서 일부러 변경한 이유가 있지 않을까 싶어 고민 고민하다 이렇게 글을 남겨봅니다.

많은 의견 부탁드립니다!

2개의 좋아요

C#으로 코딩 할 때 골치 아픈 것 중 하나가 null 참조 예외였습니다. 그렇기 때문에 참조 변수를 인자로 받는 메소드의 경우 필연적으로 null 참조 확인을 해야만 했었습니다. 이전 까지 C# 문법으로는 참조 변수가 null이 아닌 것을 언어적으로 알 길이 없었거든요.

그런데 C# 8.0 부터 타입? 형태로 null 일 수 있음을 표기하고 타입 형태일 경우 null이 될 수 없는 참조 변수로 처리하기로 결정했습니다. 이런 결정에 의해 코딩 방식을 다음처럼 유도하였습니다.

  • 타입(예: string)으로 선언했을 경우 해당 참조 필드는 생성자 또는 개체 초기화(required 키워드 사용) 시점에서 할당되어야 합니다. 그렇지 않는 경우 확인된 것처럼 경고가 발생합니다.
  • 타입?(예: string?)의 경우 null일 수 있음을 컴파일러가 알게 합니다.

이를 통해 null 참조 예외 발생을 억제하고 불필요한 null 참조 체크를 하지 않아도 되게 되었습니다.

(해당 옵션이 활성화 되었을 때 경고가 발생했다는 것은 그만큼 해당 참조 변수가 null일 수 있는 위험성이 있다는 것을 의미하기도 합니다.)

6개의 좋아요

이 기능은 컴파일러가 코드 흐름을 살펴 보고, null 값을 가질 수 있는 변수를 null 확인도 안하고 호출하는 코드를 (경고로) 콕콕 집어 주는 기능이라고 생각하시면 됩니다.

null exception 의 가능성을 컴파일 타임에 미리 체크하는 것과, 배포 후 런타임에 마주하는 것은 매우 큰 차이가 있습니다.

자신의 코드에서 nullable 경고를 많이 보고 있다면, 그 만큼 런타임에 null 예외로 앱이 뻗을 확률이 높다는 의미입니다. 타이슨 형님이 하신 말씀 기억하세요.^^

"누구나 그럴 듯한 코드를 가지고 있다. null 한테 두드려 맞기 전까지는. "

8개의 좋아요

왜? 라고 물어보신다면 코드를 작성하는 프로그래머에게 null exception이 발생할 수 있다든 것을 명시적으로 알려주기 위함이라고 답변 드릴 수 있을 것 같습니다.

말씀하는 요지는 저도 충분히 이해 합니다. 경고가뜨면 좀 지저분? 하고 거슬리죠 ㅋㅋㅋ

객체가 null 일 수 있다는 것을 ?로 표시하는 것처럼 이 객체는 null이 아니야 라고 표기하는 ! 키워드도 있으니 둘을 적절히 사용해서 경고를 없애는 것도 덜 거슬리게 만들 수 있는 방법이 아닐까합니다!

2개의 좋아요

갠적으루 몇몇 레거시 코드를 만지는 분들과 얘기를 나눠봤는데요.
아마도 이런 의문점은

그래서 뭐가 달라지는데? nullable 로 선언하면 뭐가 달라? nullable 아니면 null 체크 안 해도 됨?

였슴다…

넵. 달라지는 것 없슴다. 런타임에서는요. (여전히 null 예외는 터집니다. 당연하게도…)
nullable 선언 안 해도 런타임에서 null 이 아니라는 보장은 없어요. 런타임에서는 기존과 똑같습니다.

다만 이것을 디자인타임에 개발자가 인지하고 해결할 수 있느냐 없느냐는 큰 차이입니닷.
null 은 실제로 매우 크리티컬! 하기 떄문에 어떤 형태로든 인지해서 해결하는 것이 중요하죠.

결국 사람이 인지하기 쉽게 기능으로 지원해준다! 가 가장 큰 의미라고 보면 될 거 같아요.
그 알림을 줄만큼 중요한 문제라는 거죠.

경고가 거슬리면 해결하면 됩니다.(=ㅁ=;;; 저는 약간 강박이 있어요… all green 을 향한 집념!)
IDE 에서 경고를 띄워준다는 것은 사람이 인지할 수 있게 알림을 준다는 것이고, 그만큼
예상할 수 있는 중요한 문제라는 거니까요.

6개의 좋아요

다들 의견주셔서 감사합니다.
이해하는 데 큰 도움이 되었습니다. :slight_smile:
기본적으로 항상 null 예외처리를 하다보니 이해를 하지 못했었습니다.

정리하자면

  1. null을 명시적으로 핸들링 하여 예외처리를 줄일 수 있다.
  2. 함수의 선언부만 보고 이 함수는 null을 리턴할 수 있다는것을 바로 인지 할 수 있다.

저의 경우, 값이 없을 경우를 인지하기 위해 null이 필요한 상황이라 어느 한쪽으로 규칙을 정하기 보다 적절히 조합해서 사용해야겠습니다.

다시 한 번 다양한 의견 감사합니다 ^^!

예외 처리가 늘면 늘었지, 줄어 들 일은 없습니다. 오히려,

null 관련 처리를 빠짐 없이 하게 된다

가 가장 큰 효용입니다.

nullable 경고를 모두 해결하면, 코드는 온통 "null 체크"와 “null 회피” 코드로 도배가 됩니다.
그 만큼 코드가 튼튼해지지만, 코드가 번잡해지는 것은 피할 수 없습니다.

많은 분들이 이점 때문에 이 기능에 대한 반감이 있습니다.
null 처리를 안 하면 코드가 경고로 도배되고, 하면 번잡해지고. ^^

null 처리와 관련해서, ?. ??, ??= 연산자들이 코드를 간소화할 수 있게 도움을 줍니다.

if ( variable == null) { ... }

if (variable.Member == null) { ... }

var value = variable.Member.Value; // value 는 Value? 형식.

보다는,

var value = variable?.Member?.Value ?? new Value(); // value는 Value 형식.

개인적으로는 nullable 설정을 항상 enable 시키고, 코드에서도 “경고 off 스위치(! 연산자)” 를 가급적 사용하지 말라고 권하고 싶습니다. 결국엔 그곳이 null 예외 구멍이 될테니까요.

3개의 좋아요