26. Nullable<T> 내부 구조와 boxing 특수 처리, lifted operator

난이도 중 해설 보기 →

결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커 (A)(B) 는 주목 위치 힌트다.

결함 코드 · C#
// 문제 26 — Nullable<T> 내부 구조와 boxing 시의 특수 처리, lifted operator
//
// 아래는 게임 서버에서 플레이어의 "선택적 보너스 스탯"을 int?(Nullable<int>)로
// 표현하고, 이를 object로 박싱/언박싱하거나 서로 비교·연산하는 코드다.
//
// (A) Nullable<T>는 실제로 HasValue(bool)와 Value(T) 두 필드만 가진 struct다.
// (B) hasBonus 가 null인 상태에서 boxing이 일어나는 지점이 있다.
// (C) 들어올림 연산자(lifted operator)로 처리되는 비교/산술 연산이 있다.
//
// 과제:
// 1. bonus1 (값이 있는 int?)을 object로 박싱한 뒤 다시 언박싱하는 코드에서,
//    박싱된 object의 실제 런타임 타입(GetType())이 무엇으로 나오는지 예측하라.
// 2. bonus2 (값이 없는, 즉 null인 int?)을 object로 박싱하면 그 결과가
//    정확히 어떤 값/타입이 되는지 예측하라("boxed Nullable<int> with HasValue=false"
//    같은 객체가 되는지, 아니면 다른 무언가가 되는지).
// 3. boxedNull == null 비교 결과와 boxedNull is int 패턴 매칭 결과를 예측하라.
// 4. bonus1 + bonus2 (들어올림 산술 연산자)의 결과와, bonus1 == bonus2,
//    bonus2 == null 의 결과를 각각 예측하라.
// 5. GetValueOrDefault()와 그냥 Value를 사용했을 때(HasValue가 false인 경우)의
//    차이를 예측하라(예외가 나는지, 어떤 예외인지).
//
// 아래 코드는 콘솔 앱에서 컴파일·실행 가능하다 (C# 8+ 기준, dotnet run).

using System;

class BonusStatSystem
{
    static void Main()
    {
        int? bonus1 = 15;
        int? bonus2 = null;

        Console.WriteLine("--- 1. 값이 있는 Nullable<int> 박싱/언박싱 ---");
        object boxed1 = bonus1;
        Console.WriteLine($"boxed1.GetType() = {boxed1.GetType()}");
        int unboxed1 = (int)boxed1;
        Console.WriteLine($"unboxed1 = {unboxed1}");

        Console.WriteLine("--- 2. 값이 없는(null) Nullable<int> 박싱 ---");
        object boxedNull = bonus2;
        Console.WriteLine($"boxedNull == null : {boxedNull == null}");
        Console.WriteLine($"boxedNull is int   : {boxedNull is int}");

        Console.WriteLine("--- 3. 들어올림 연산자(lifted operator) ---");
        int? sum = bonus1 + bonus2;
        Console.WriteLine($"bonus1 + bonus2 = {(sum.HasValue ? sum.Value.ToString() : "null")}");

        bool eq1 = bonus1 == bonus2;
        bool eq2 = bonus2 == null;
        Console.WriteLine($"bonus1 == bonus2 : {eq1}");
        Console.WriteLine($"bonus2 == null   : {eq2}");

        int? bonus3 = 15;
        bool eq3 = bonus1 == bonus3;
        Console.WriteLine($"bonus1 == bonus3 : {eq3}");

        Console.WriteLine("--- 4. GetValueOrDefault() vs Value ---");
        int safeValue = bonus2.GetValueOrDefault();
        Console.WriteLine($"bonus2.GetValueOrDefault() = {safeValue}");

        try
        {
            int riskyValue = bonus2.Value;
            Console.WriteLine($"bonus2.Value = {riskyValue}");
        }
        catch (InvalidOperationException e)
        {
            Console.WriteLine($"bonus2.Value 접근 시 예외 발생: {e.GetType().Name}");
        }

        Console.WriteLine("--- 5. typeof(int?) 와 Nullable.GetUnderlyingType ---");
        Type nullableType = typeof(int?);
        Console.WriteLine($"typeof(int?) = {nullableType}");
        Console.WriteLine($"Nullable.GetUnderlyingType(typeof(int?)) = {Nullable.GetUnderlyingType(nullableType)}");
    }
}
내 리뷰 · C#
내 답안 · 자동 저장

작성 후 위 해설 보기에서 모범 해설과 대조하세요.