CodeGym /행동 /C# SELF /값 타입을 위한 Nullable 타입

값 타입을 위한 Nullable 타입

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

1. 소개

이런 상황을 한번 상상해봐. 코드에서 고양이 데이터를 저장하고 있어. 그리고 고양이의 나이뿐만 아니라 "데이터 없음", "나이 모름" 같은 상태도 저장하고 싶어. 0을 저장할 수도 있겠지만, 0은 실제로 유효한 나이잖아.

int age = 0; // 고양이 나이. 근데 0이 뭐야? 아기 고양이? 아니면 "모름"?

문제는 int는 정수만 받을 수 있고, "데이터 없음" 같은 건 정수에선 불가능하다는 거야. 만약 나이가 문자열이면 null을 넣을 수 있겠지. 근데 숫자에선 그게 안 돼:

int age = null; // 오류! int 타입 변수에 null을 넣을 수 없어

이건 값 타입 (struct류, 예: int, double, DateTime, bool)은 항상 뭔가 값을 가지고 있기 때문이야. 얘네는 "비어 있음" 상태가 없어 (참조 타입은 null이 그냥 객체 없음이지만).

실생활 예시:
이 제한을 우회하려고 개발자들이 "특별한" 값을 만들기도 해: 예를 들어 -1이나 int.MaxValue를 "값 없음"으로 쓰는 거지. 근데 이건 별로야. 헷갈리기도 쉽고, 진짜 값이랑 구분도 힘들어.

2. Nullable 타입: "null"이 될 수 있는 타입

아이디어

만약 일반 숫자(그리고 모든 값 타입)가 값뿐만 아니라 null도 가질 수 있다면 어떨까?
C#에서는 이걸 Nullable<T>라는 특별한 래퍼 클래스로 구현했어. 이 클래스는 T 타입 값이나 아무것도 없는 상태(null) 둘 중 하나를 가질 수 있어.

문법

int? age = null; // age 변수는 숫자도 되고 null도 될 수 있어
?로 nullable 타입 선언하기

C# 컴파일러는 이런 코드를 보면 사실상 이렇게 인식해:

Nullable<int> age = new Nullable<int>(); // age 변수는 값이 없음

혹시 값을 명시적으로 넣고 싶으면:

Nullable<int> age = new Nullable<int>(42); // age에 42가 들어감

이렇게 물음표를 붙이면 어떤 값 타입이든 nullable 버전으로 바뀌는 거야:

  • int? (이건 Nullable<int>랑 똑같아)
  • double?
  • DateTime?
  • 그리고 다른 struct들도 다 가능

가장 많이 쓰는 struct용 Nullable 래퍼

일반 타입 Nullable 타입 예시 코드
int
int?
int? a = null;
double
double?
double? x = 3.14;
bool
bool?
bool? ok = null;
DateTime
DateTime?
DateTime? d = null;

래퍼 클래스를 써서 길게 쓸 수도 있어:


Nullable<int> pages = null;
        
긴 버전

근데 int?가 훨씬 짧고, 그래서 더 멋져.

3. Nullable 타입 사용법

값 할당과 체크

null 할당은 참조 타입이랑 똑같이 돼:

선언과 할당

int? temperature = null;
temperature = 25;

null 체크

nullable 타입에 진짜 값이 있는지 어떻게 알 수 있을까?

if (temperature != null)
{
    Console.WriteLine($"온도: {temperature}");
}
else
{
    Console.WriteLine("온도 데이터 없음");
}

Nullable 타입의 속성: .HasValue.Value

nullable 타입엔 중요한 속성 두 개가 있어:

  • .HasValue — 변수에 뭔가 들어있으면(null 아니면) true를 반환해.
  • .Value — 값이 있으면 그 값을 주고, 없으면 예외가 나와.
int? temperature = null;
if (temperature.HasValue) //예외 안 남!
{
    Console.WriteLine($"온도: {temperature.Value}°C");
}
else
{
    Console.WriteLine("온도 모름");
}

이 코드는 잘 돌아가: temperature는 null이랑 같지 않고, 내부에 null을 담고 있어. Nullable 타입의 HasValue 속성은 언제든 쓸 수 있어. 근데 .Value를 값 없이 꺼내려 하면 InvalidOperationException 예외가 나니까, 꼭 값 있는지 먼저 체크하자!

간단 출력 문법

많은 경우 그냥 nullable 타입 변수를 써도 C#이 알아서 처리해줘:

int? hours = null;
Console.WriteLine(hours); // 아무것도 안 나옴(그냥 빈칸)
hours = 10;
Console.WriteLine(hours); // 10이 나옴

4. 연산과 nullable 타입: 산술, 비교, 변환

연산: 어떻게 될까?

피연산자 중 하나라도 nullable이면 결과도 nullable이야.
그리고 피연산자 중 하나가 null이면 결과도 null이 돼.

int? a = 5;
int? b = null;
int? sum = a + b; // sum == null

int? c = 10;
int? d = 15;
int? total = c + d; // total == 25

비교 연산

nullable 타입을 일반 숫자랑 비교할 수 있어:

int? score = null;
if (score > 0) Console.WriteLine("좋은 결과야!");
else Console.WriteLine("결과 없음"); // 이쪽이 실행됨

score가 null이면 score > 0 조건은 false야.

명시적/암시적 변환

  • 일반 타입에서 nullable로: 자동 변환.
  • nullable에서 일반 타입으로: null이 아니어야만 가능(아니면 예외).
int? x = 3;
int y = x.Value; // x가 null 아니면 Ok

// 암시적 변환
int? z = y;

5. Nullable과 메서드: 파라미터와 반환값

nullable 값 반환하기

메서드가 항상 결과를 반환할 수 없는 경우, 반환 타입을 nullable로 쓰면 돼:

// 메서드가 로그인으로 유저를 찾아서 나이를 반환, 못 찾으면 null
int? FindUserAge(string login)
{
    // ... 여기서 찾는 로직
    return null; // 못 찾았을 때
}

Nullable 파라미터

nullable 값을 파라미터로 받을 수도 있어. "있을 수도, 없을 수도 있음"을 명확히 보여주는 거지.

void PrintTemperature(int? temp)
{
    if (temp == null)
        Console.WriteLine("온도 모름");
    else
        Console.WriteLine($"온도: {temp} 도");
}
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION