안녕하세요. 이번 글에서는 C#의 null 처리 연산자인 ?., ??, ??=에 대해 알아보겠습니다.
null 검사를 위한 if 문이 겹겹이 쌓이면 코드가 길어지고 읽기 어려워집니다. 세 연산자를 사용하면 null 검사를 한 줄로 줄일 수 있습니다.
한눈에 보기
| 연산자 | 이름 | 동작 |
|---|---|---|
| ?. | null 조건 연산자 | 왼쪽이 null이면 멤버 접근을 건너뛰고 null 반환 |
| ?? | null 병합 연산자 | 왼쪽이 null이면 오른쪽 값 사용 |
| ??= | null 병합 할당 연산자 | 왼쪽이 null일 때만 오른쪽 값 할당 (C# 8.0) |
예제 코드
using System;
class Person
{
public string Name { get; set; }
public Address Address { get; set; }
}
class Address
{
public string City { get; set; }
}
class Program
{
static void Main()
{
Person p = new Person();
// before : null 검사 중첩
string city1 = null;
if (p != null && p.Address != null)
city1 = p.Address.City;
// after : ?. 사용
string city2 = p?.Address?.City;
// ?? : 기본값 지정
string name = p.Name ?? "이름 없음";
// ??= : null일 때만 할당
p.Name ??= "Guest";
p.Name ??= "Other"; // 이미 값이 있으므로 변경되지 않음
Console.WriteLine(city2 ?? "city is null");
Console.WriteLine(name);
Console.WriteLine(p.Name);
}
}
실행 결과는 다음과 같습니다.
city is null
이름 없음
Guest
활용과 주의할 점
- 배열·컬렉션에는 ?[ ]를 씁니다. list?[0]
- 이벤트 호출은 Changed?.Invoke(this, e) 형태로 null 검사와 호출을 함께 처리합니다.
- 값 형식에 ?.를 쓰면 결과가 nullable이 됩니다. int? len = str?.Length;
- ?? throw 형태로 필수 값을 검사할 수 있습니다. var v = arg ?? throw new ArgumentNullException(nameof(arg));
- ?.는 null일 때 뒤쪽 호출 전체를 건너뛰지만, 그 결과를 다시 쓰는 곳에서는 null이 될 수 있다는 점을 잊으면 안 됩니다.
정리
- ?. : null이면 접근하지 않고 null 반환
- ?? : null이면 대체값 사용
- ??= : null일 때만 할당
이상으로 C#의 null 처리 연산자에 대해 간단히 알아보았습니다.