CodeGym /행동 /C# SELF /C#에서 여러 개의 catch와 필터 사용하기

C#에서 여러 개의 catch와 필터 사용하기

C# SELF
레벨 13, 레슨 4
사용 가능

1. 소개

프로그램이 Hello, world!보다 조금만 복잡해지면, 다양한 타입의 에러를 각각 다르게 처리해야 하는 상황이 금방 찾아와. 예를 들어 파일, 네트워크, DB를 다루다 보면 에러 상황마다 반응이 달라야 하잖아. 파일이 없으면 다른 파일을 고르라고 안내할 수 있고, 네트워크 에러면 "다시 시도" 버튼이나 "케이블 확인해봐, 혹시 고양이가 또 물어뜯었을지도?" 같은 위로 메시지를 보여줄 수도 있지.

C#에서는 이런 걸 여러 개의 catch 블록을 연달아 써서 처리해. 각 블록은 자신만의 예외 타입(혹은 그 자식 타입)에 특화되어 있어.

여러 개 catch의 구조


try
{
    // 여기서 여러 가지 예외가 발생할 수 있는 코드
}
catch (FileNotFoundException ex)
{
    Console.WriteLine($"파일을 찾을 수 없음: {ex.Message}");
}
catch (IOException ex) // FileNotFoundException이 아니면 모든 입출력 에러를 잡음
{
    Console.WriteLine($"입출력 에러: {ex.Message}");
}
catch (Exception ex)
{
    Console.WriteLine($"뭔가 잘못됨: {ex.Message}");
}
다양한 에러 타입을 위한 여러 개 catch 블록

중요! 컴파일러는 위에서 아래로 블록을 따라가면서 타입이 맞는 첫 번째 블록을 골라. FileNotFoundException이 잡히면 그 아래 블록들은 실행되지 않아.

"체인" 일러스트

예외 타입 어떤 블록이 잡을까?
FileNotFoundException 첫 번째 catch
IOException (다른 종류) 두 번째 catch
ArgumentException 세 번째(공통) catch

왜 섞으면 안 될까?
가장 "넓은" 트랩, 예를 들어 catch (Exception) 같은 건 항상 마지막에 둬야 해. 그렇지 않으면 모든 예외를 너무 일찍 잡아버려서, 더 구체적인 catch까지 실행이 안 돼.

이건 마치 건물에서 토스터가 타서 화재 경보기가 울렸다고 모든 화재 감지기를 꺼버리는 것과 같아. 그러면 다음 화재는 시스템이 못 알아채지.

실전 예시

using System;
using System.IO;

class Program
{
    static void Main()
    {
        try
        {
            double result = CalculateAverageAgeFromFile("users.txt");
            Console.WriteLine($"평균 나이 — {result}");
        }
        catch (FileNotFoundException ex)
        {
            Console.WriteLine("에러: 파일을 찾을 수 없음. 경로를 확인해줘.");
        }
        catch (FormatException ex)
        {
            Console.WriteLine("데이터 에러: 나이를 읽을 수 없어.");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"다른 에러: {ex.Message}");
        }
    }

    static double CalculateAverageAgeFromFile(string filePath)
    {
        // (구현: 파일 읽고, 나이 파싱하고, 평균 계산)
        // ...
        throw new NotImplementedException();
    }
}

여기서는 파일이 없을 때(FileNotFoundException), 파일에 "이상한" 데이터가 있을 때(FormatException) 각각 따로 처리해. 나머지 경우는 "예비" 세 번째 블록이 다 받아줘.

2. catch 필터: 미묘한 차이 잡기

여러 개 catch 블록도 편리하지만, 가끔은 그걸로 부족할 때가 있어. 같은 예외 타입 안에서도 상황에 따라 다르게 반응하고 싶을 때가 있거든.

예를 들어, 인터넷이 끊겨서 네트워크가 안 되면 재연결을 시도할 수 있고, 서버가 그냥 응답이 없으면 다른 메시지를 보여줄 수도 있지.

이럴 때 catch 필터가 등장해 — C#의 진짜 꿀기능! 타입뿐만 아니라 추가 조건까지 걸어서 예외를 잡을 수 있어.

when 필터 문법


catch (IOException ex) when (ex.Message.Contains("디스크 없음"))
{
    Console.WriteLine("앗! 혹시 USB를 뽑은 것 같아.");
}
catch (IOException ex)
{
    Console.WriteLine("다른 입출력 에러: " + ex.Message);
}
예외 조건을 세밀하게 잡는 catch when 필터

여기서 첫 번째 블록은 IOException 중에서 메시지에 "디스크 없음"이 들어간 것만 잡아. 나머지는 두 번째 블록으로 넘어가.

실전에서의 활용

필터는 네트워크 에러처럼 예외의 내부 속성에 따라 "재시도"할지, 그냥 에러만 알릴지 결정해야 할 때 특히 유용해.

또 다른 예시: 파일 파싱 메서드에서 FormatException이 발생했을 때, 그냥 "에러"만 띄우는 게 아니라, 만약 나이 값이 문제라면 따로 안내하고 싶을 때도 쓸 수 있어(예: 나이가 "abc"처럼 숫자가 아니게 적혀 있을 때).

catch (FormatException ex) when (ex.Message.Contains("나이"))
{
    Console.WriteLine("에러: 나이를 읽을 수 없어. 데이터를 확인해줘.");
}
catch (FormatException ex)
{
    Console.WriteLine("데이터 포맷 에러: " + ex.Message);
}

필터와 성능

필터는 진짜 편하지만, catch 블록에 들어가기 전에 조건이 먼저 계산된다는 걸 기억해. 조건이 안 맞으면 블록 내부는 아예 실행되지 않아.

참고로, 만약 when 조건식에서 자체적으로 예외가 발생하면(예: 0으로 나누기), 그 예외는 해당 catch 블록에서 절대 잡히지 않아. 조심해서 써야 해.

3. 여러 개 catch와 필터를 같이 쓰기

프로젝트에서 예외 타입뿐 아니라 내부 상태까지 구분해서 처리해야 할 때가 있어. 예를 들어 IOException이 발생했을 때, 파일 시스템 에러가 권한 문제인지, 디스크 용량 부족인지에 따라 다르게 반응하고 싶을 때 말이야.


try
{
    File.AppendAllText("log.txt", "새로운 기록\n");
}
catch (IOException ex) when (ex.Message.Contains("공간 없음"))
{
    Console.WriteLine("에러: 디스크에 공간이 부족해!");
}
catch (UnauthorizedAccessException)
{
    Console.WriteLine("에러: 파일 쓸 권한이 없어. 관리자 권한으로 실행해줘.");
}
catch (IOException ex)
{
    Console.WriteLine("다른 디스크 에러: " + ex.Message);
}
다양한 catch 타입과 필터를 조합한 예시

여기서는 필터와 에러 타입 분리를 같이 써. 이런 유연함은 복잡한 앱에서 자주 발생하는 에러에 대해 친절하게 안내할 때 특히 좋아.

4. 필터와 여러 개 catch의 특징과 주의점

  • catch 필터에서는 예외 변수(ex)를 쓸 수 있지만, 값을 바꿀 수는 없어.
  • when 안에서 예외를 던지면, 그 예외는 해당 catch에서 절대 잡히지 않고, 스택을 타고 위로 올라가. 필터 쓸 때 조심!
  • 필터의 조건도 일종의 "계약"이야: 같이 일하는 동료도 모든 IOException이 잡히는 게 아니라, 조건이 맞을 때만 잡힌다는 걸 알아야 해.
  • 메서드 전체에 catch 하나만 두고 필터로만 구분하면, "남는" 예외를 아예 못 잡을 수도 있어. 헷갈리면 그냥 여러 개 블록을 명시적으로 쓰는 게 안전해.
  • 큰 앱에서는 필터로 "치명적 에러만 로깅" 같은 중앙집중식 로직도 만들 수 있어.

5. 면접과 실무에서의 시나리오

필터랑 여러 개 catch를 아는 건 단순히 clean code 점수 올리려고 배우는 게 아니야. 실제로 대형, 복잡, 분산 앱을 다루는 포지션 면접에서 이런 걸 물어볼 수도 있어.

예시 질문:

  • C#에서 파일 읽기 에러를 상황별(파일 없음, 디스크 점유, 데이터 손상)로 다르게 안내하려면 어떻게 처리해?
  • 공통 catch (Exception) 블록을 썼을 때, 중요한 에러를 "묻어버리지" 않으려면 어떻게 해야 해?
  • catch 필터는 왜 필요해? 그 안에 throw를 쓸 수 있을까?
2
과제
C# SELF, 레벨 13, 레슨 4
잠금
여러 개의 `catch`를 사용한 예외 처리
여러 개의 `catch`를 사용한 예외 처리
2
과제
C# SELF, 레벨 13, 레슨 4
잠금
catch 필터 사용하기
catch 필터 사용하기
1
설문조사/퀴즈
예외와의 첫 만남, 레벨 13, 레슨 4
사용 불가능
예외와의 첫 만남
호출 스택이랑 직접 예외 만들기
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION