← SEARCHABLE ARCHIVE
C# · 2026-08-05

C# 기초부터 마스터까지 — 7화

예외와 IDisposable로 자원 수명 관리하기

INTERACTIVE READING MODE →

본 블로그 작성 글들은, 강의를 목표로 하고 제작되었습니다. 또한 작성된 글의 정보도 틀렸을 수 있으니, 주의해주세요.

실패할 수 있는 코드는 실패한 뒤의 상태까지 설계해야 한다. 예외를 잡는 것뿐 아니라 파일과 연결 같은 자원이 어떤 경로에서도 정리되는지가 중요하다.

예상 가능한 실패

bool TrySpendGold(int amount)
{
    if (amount < 0 || Gold < amount)
    {
        return false;
    }

    Gold -= amount;
    return true;
}

골드 부족처럼 자주 일어나는 결과는 bool이나 별도의 결과 타입으로 표현할 수 있다. 예외는 파일 손상이나 계약 위반처럼 현재 흐름에서 정상 처리하기 어려운 실패에 사용한다.

예외 처리

try
{
    string json = File.ReadAllText(path);
    settings = JsonSerializer.Deserialize<Settings>(json)
        ?? throw new InvalidDataException("Settings are empty");
}
catch (IOException error)
{
    logger.Log(error.Message);
    settings = Settings.CreateDefault();
}

처리할 수 있는 예외만 잡아 복구하거나 더 의미 있는 정보와 함께 위로 전달한다. 내용을 처리하지 않은 채 모든 예외를 잡으면 버그가 조용히 숨을 수 있다.

IDisposable과 using

using FileStream stream = File.OpenRead(path);
using var reader = new StreamReader(stream);

string text = reader.ReadToEnd();

using 범위를 벗어나면 Dispose가 호출된다. 정상 반환뿐 아니라 예외가 발생한 경로에서도 파일 핸들이 정리된다.

GC는 관리 객체의 메모리를 회수하지만 파일, 소켓, 네이티브 버퍼를 즉시 닫아주겠다는 약속은 아니다. 이런 자원을 소유하는 타입은 IDisposable 계약을 제공해야 한다.

상태를 나중에 교체하기

Settings LoadSettings(string path)
{
    string json = File.ReadAllText(path);
    return JsonSerializer.Deserialize<Settings>(json)
        ?? throw new InvalidDataException("Invalid settings");
}

Settings loaded = LoadSettings(path);
currentSettings = loaded;

새 설정을 완전히 만든 뒤 기존 설정과 교체하면 로딩 중 실패해도 기존 상태가 남는다. 예외 처리는 catch의 개수보다 실패 전후의 상태와 자원 수명을 예측 가능하게 만드는 일이다.