⚠️ NullReferenceException: Object reference not set to an instance of an object
C#에서 NullReferenceException은 가장 흔하게 발생하는 런타임 오류 중 하나다. 객체가 null인 상태에서 멤버에 접근하려 할 때 발생한다. 이 오류는 컴파일 타임에 감지되지 않아 런타임에 예기치 못한 크래시를 일으킬 수 있다.
개요
- 증상:
NullReferenceException: Object reference not set to an instance of an object - 주요 원인:
null인 객체의 멤버(메서드, 속성, 필드)에 접근 - 해결 방향: null 체크, null 조건부 연산자(
?.), null 병합 연산자(??) 활용
언제 발생하나
대표적인 상황은 다음과 같다.
- 초기화되지 않은 참조 변수에 접근
- 메서드가
null을 반환하는 경우를 처리하지 않음 - 컬렉션이나 배열이
null인 상태에서 요소 접근 - 이벤트 핸들러가
null인 상태에서 호출
재현 코드(오류 발생 패턴)
class Program
{
static void Main(string[] args)
{
Person person = null;
// NullReferenceException 발생
string name = person.Name; // person이 null이므로 오류
int age = person.GetAge(); // 마찬가지로 오류
}
}
class Person
{
public string Name { get; set; }
public int GetAge() => 25;
}
이 코드는 person이 null인 상태에서 Name 속성과 GetAge() 메서드에 접근하려 하므로 런타임에 예외가 발생한다.
해결 원칙
1) null 체크를 명시적으로 수행한다
가장 기본적인 방법은 객체가 null인지 확인한 후 접근하는 것이다.
Person person = GetPerson();
if (person != null)
{
string name = person.Name;
int age = person.GetAge();
}
2) null 조건부 연산자(?.)를 활용한다
C# 6.0부터 도입된 null 조건부 연산자는 객체가 null이면 전체 표현식이 null을 반환한다.
Person person = GetPerson();
// person이 null이면 name도 null이 됨
string name = person?.Name;
// 메서드 호출도 안전하게 처리
int? age = person?.GetAge();
3) null 병합 연산자(??)로 기본값 제공한다
null 병합 연산자는 왼쪽 피연산자가 null이면 오른쪽 값을 반환한다.
Person person = GetPerson();
// person이 null이면 "Unknown" 반환
string name = person?.Name ?? "Unknown";
// 숫자 타입에도 적용 가능
int age = person?.GetAge() ?? 0;
4) null 병합 할당(??=)으로 초기화한다
C# 8.0부터 도입된 null 병합 할당 연산자는 변수가 null일 때만 값을 할당한다.
Person person = GetPerson();
person ??= new Person { Name = "Default" };
유사 사례
컬렉션 null 체크
List<string> items = GetItems();
// 잘못된 방법: items가 null이면 오류
int count = items.Count;
// 올바른 방법
int count = items?.Count ?? 0;
이벤트 핸들러 null 체크
public event EventHandler SomethingHappened;
protected virtual void OnSomethingHappened()
{
// 잘못된 방법
SomethingHappened(this, EventArgs.Empty); // null이면 오류
// 올바른 방법
SomethingHappened?.Invoke(this, EventArgs.Empty);
}
문자열 null 체크
string text = GetText();
// 잘못된 방법
int length = text.Length; // text가 null이면 오류
// 올바른 방법
int length = text?.Length ?? 0;
추가 고려사항
nullable 참조 타입 (C# 8.0+)
C# 8.0부터 nullable 참조 타입을 활성화하면 컴파일 타임에 null 참조 경고를 받을 수 있다.
#nullable enable
class Program
{
static void Main(string[] args)
{
Person? person = GetPerson(); // ? 표시로 nullable 명시
// 컴파일러가 null 체크를 요구함
if (person != null)
{
string name = person.Name; // 안전
}
}
}
ArgumentNullException 사용
메서드 파라미터가 null인 경우 NullReferenceException 대신 ArgumentNullException을 던지는 것이 더 명확하다.
public void ProcessPerson(Person person)
{
if (person == null)
throw new ArgumentNullException(nameof(person));
// 처리 로직
}