CodeGym /행동 /C# SELF /null 다루기: 연산자 ??, ?., ?, !, default

null 다루기: 연산자 ??, ?., ?, !, default

C# SELF
레벨 14 , 레슨 3
사용 가능

1. null 병합 연산자 (??)

nullable 타입에 대해 잘 알기 위해서는 간결하고 안전한 코드를 쓸 줄 알아야 해. C#에는 이걸 도와주는 두 개의 엄청 유용한 연산자가 있어: null 병합 연산자(??)null-조건부 연산자(?.).

?? 연산자null일 수 있는 변수에 “기본값”을 지정할 수 있게 해줘.

예를 들어, 사용자 이름이 null일 수도 있다고 해보자. 만약 진짜 null이면 "손님"을 보여주고 싶을 때 이렇게 할 수 있어:

string userName = null;
string displayName = userName != null ? userName : "손님";
null 체크의 고전적인 예시

?? 연산자를 쓰면 더 간단하게 쓸 수 있어:

string userName = null;
string displayName = userName ?? "손님";
기본값으로 ?? 사용하기

작동 방식:

  • 왼쪽 표현식이 null이 아니면 그 값을 반환해.
  • 왼쪽이 null이면 오른쪽 값을 써.

다른 예시도 있어:

int? age = null;
int displayAge = age ?? -1; // -1 — 기본값
Console.WriteLine(displayAge); // -1 출력

string input = null;
string name = input ?? "손님";
Console.WriteLine($"안녕, {name}!"); // 안녕, 손님!

연산자 체이닝

??를 체인처럼 여러 번 쓸 수도 있어:

string result = str1 ?? str2 ?? "기본값";
?? 연산자 체이닝

str1null이 아니면 그걸 쓰고, 아니면 str2를, 그것도 null이면 "기본값" 문자열을 써.

2. null-조건부 연산자 (?.)

또 자주 나오는 상황이, 객체가 null이 아닐 때만 메서드를 호출하거나 프로퍼티에 접근하고 싶을 때야. 예를 들어:

User user = null;
string displayName = user != null ? user.Name : null;
프로퍼티 접근 전에 null 체크하는 고전적인 예시

?. 연산자를 쓰면 더 간단해져:

User user = null;
string displayName = user?.Name;
null-조건부 연산자 ?.

usernull이면 에러가 안 나고 그냥 null을 반환해.

예시:

User user = null;

// ?. 없이 — 에러 발생
// Console.WriteLine(user.Name); // NullReferenceException

Console.WriteLine(user?.Name); // 안전 — 빈 문자열이나 아무것도 출력 안 됨

Console.WriteLine(user?.GetProfileInfo()); // 이것도 마찬가지

User[] users = null;
int? count = users?.Length; // users == null이면 null

연산자 체이닝

이렇게 "체인"도 만들 수 있어:


string domain = company?.Director?.Email?.Split('@')?[1];
중첩 프로퍼티에 안전하게 접근하는 ?. 체이닝

경로 중간에 뭐라도 null이면, 예외 안 나고 그냥 null을 반환해.

??와 조합

?.??는 같이 쓰면 진짜 좋아:


string display = user?.Name ?? "알 수 없음";
안전하게 기본값 출력하기

useruser.Namenull이면 "알 수 없음"이 출력돼.

3. ! 이건 뭐고 언제 써?

null 경고 억제 연산자

최신 C# 버전(NRT 켜져 있을 때)에서는, null일 수 있는 변수에 접근하면 컴파일러가 친절하게 경고를 해줘. 근데 네가 진짜로 "이건 무조건 null 아님!"이라고 확신할 때는 경고 억제 연산자 !를 쓸 수 있어.


string? possibleNull = GetUserNameMaybeNull();
Console.WriteLine(possibleNull.Length); // Warning: null일 수 있음

Console.WriteLine(possibleNull!.Length); // 컴파일러는 조용, 근데 진짜 null이면 예외 터짐

중요: !는 에러를 막아주지 않아 — 그냥 컴파일러한테 "믿어줘"라고 말하는 거야. 만약 진짜 null이면 NullReferenceException이 터져.

언제 쓰면 안 될까?

!를 아무 생각 없이 쓰지 마. 좋은 스타일은 최대한 안 쓰는 거야. null이 불가능하거나, 명확하게 처리되도록 코드를 짜는 게 더 좋아.

4. default — 타입의 "기본값" 얻기

가끔은 그냥 변수를 초기 상태로 "리셋"하고 싶을 때가 있어. 직접 0, false, null을 쓰기 귀찮을 때 말이지.

이럴 때 default 키워드를 쓰면 돼.

int a = default;            // a == 0
bool flag = default;        // flag == false
string s = default;         // s == null
double? d = default;        // d == null
변수 리셋에 default 사용하기

네 미니 앱에서 이름이나 나이를 리셋할 때도 쓸 수 있어:

userName = default; // null
userAge = default;  // null (userAge가 int?일 때)

5. 차이점과 뉘앙스: ?, !, default

경험 많은 개발자도 ?, !, default가 한데 나오면 헷갈릴 때가 있어. 누가 누군지 정리해보자.

?null을 허용한다는 뜻

  • 값 타입: int? x — 이제 x는 null이 될 수 있어.
  • 참조 타입: string? s — 이 변수는 null일 수 있다고 명시(NRT 모드에서).

!null이 절대 아니라고 주장

  • user!.Nameuser는 절대 null이 아니라고 컴파일러에게 약속하는 거야.
  • Nullable Reference Types 모드에서만 동작해.

default — "기본값"을 달라는 뜻

  • int x = default; — x는 0이 돼
  • string s = default; — s는 null이 돼

비교:

문법 이게 뭐야? 어디서 써? null이랑 무슨 관계?
int?
nullable 값 타입 어디서나 null을 넣을 수 있음
string?
nullable 참조 타입 (NRT) NRT 모드에서 null을 넣을 수 있음
!
null-forgiving operator NRT 모드에서 경고 억제
default
기본값 어디서나 참조 타입은 null

6. ?, !, default 쓸 때 흔한 실수

실수 1: !가 null을 "치유"한다고 착각함.
사실 !는 그냥 컴파일러가 뭐라 안 하게 하는 거야. 값이 진짜 null이면 프로그램은 NullReferenceException으로 터져.

실수 2: .Value 쓰기 전에 .HasValue 체크를 까먹음.
특히 int?, bool? 같은 nullable 타입에서. 체크 안 하면 InvalidOperationException 예외가 나올 수 있어.

실수 3: "특별한" 0 의미가 필요한데 default를 써버림.
예를 들어 0이나 false가 실제 값일 수도 있는데, 이걸 "비어있음" 신호로 오해하면 논리적 오류가 생길 수 있어.

실수 4: NRT 모드에서 참조 타입에 ?를 안 쓰거나, 너무 남발함.
누군가는 ?를 까먹어서 컴파일러 경고가 잔뜩 나오고, 또 누군가는 ?를 남발해서 null이 절대 안 나오는 곳에도 붙여. 둘 다 코드 가독성과 신뢰성을 떨어뜨려.

코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION