Search

이것이 C#이다: 12장 - 예외 처리하기

서론

개발에서 오류는 피할 수 없는 현실입니다. 특히 다양한 외부 요인과 상호작용하는 복잡한 시스템에서는 더욱 그렇습니다. C#에서는 이러한 예기치 못한 상황을 '예외(Exception)'라고 부르며, 이를 효과적으로 다루는 것이 안정적이고 견고한 애플리케이션을 만드는 핵심입니다.
이번 포스트에서는 C#의 예외 처리 방식에 대해 살펴보겠습니다. 예외의 기본 개념부터 관련 기능까지, 코드 예시와 함께 단계별로 학습해 보겠습니다.

본론

1. 예외(Exception)의 개념

예외는 프로그램 실행 중 발생하는 예기치 못한 상황을 나타냅니다. 이는 프로그래머가 예상한 정상적인 흐름을 벗어나는 사건을 의미합니다. 예를 들어, 배열의 범위를 벗어난 접근, 0으로 나누기, 파일을 찾을 수 없는 경우 등이 있습니다.
int[] numbers = new int[5]; // 아래 코드는 IndexOutOfRangeException을 발생시킵니다. // numbers[10] = 50;
C#
복사

2. try-catch로 예외 잡기

C#에서는 try-catch 구문을 사용하여 예외를 처리합니다. try 블록에는 예외가 발생할 수 있는 코드를, catch 블록에는 예외 발생 시 실행될 코드를 작성합니다.
try { int result = 10 / 0; // 0으로 나누기 시도 } catch (DivideByZeroException e) { Console.WriteLine($"오류 발생: {e.Message}"); }
C#
복사

3. System.Exception 클래스

C#의 모든 예외 클래스는 System.Exception 클래스로부터 상속받습니다. 이 클래스는 예외의 기본적인 속성과 메서드를 제공합니다.
주요 속성들:
Message: 예외에 대한 설명
StackTrace: 예외가 발생한 메서드 호출 스택
InnerException: 현재 예외의 원인이 된 예외
try { throw new Exception("일반적인 오류 발생"); } catch (Exception e) { Console.WriteLine($"예외 메시지: {e.Message}"); Console.WriteLine($"스택 추적: {e.StackTrace}"); }
C#
복사
하지만 Exception 클래스로 모든 예외를 잡는 것은 권장되지 않습니다. 가능한 한 구체적인 예외 타입을 사용하여 처리하는 것이 좋습니다.

4. 예외 던지기 (throw)

throw 키워드를 사용하여 명시적으로 예외를 발생시킬 수 있습니다. 이는 특정 조건에서 프로그램의 정상적인 흐름을 중단하고 싶을 때 유용합니다.
static void ValidateAge(int age) { if (age < 0) { throw new ArgumentException("나이는 0보다 작을 수 없습니다."); } } try { ValidateAge(-5); } catch (ArgumentException e) { Console.WriteLine($"유효하지 않은 나이: {e.Message}"); }
C#
복사
C# 7.0부터는 throw를 식으로도 사용할 수 있어, 더욱 간결한 코드 작성이 가능해졌습니다:
int? age = null; int validAge = age ?? throw new ArgumentNullException(nameof(age));
C#
복사

5. finally 블록

finally 블록은 예외 발생 여부와 관계없이 항상 실행되는 코드 블록입니다. 주로 리소스 해제와 같은 정리 작업에 사용됩니다.
FileStream file = null; try { file = File.OpenRead("nonexistent.txt"); } catch (FileNotFoundException e) { Console.WriteLine($"파일을 찾을 수 없습니다: {e.Message}"); } finally { if (file != null) { file.Close(); } }
C#
복사
finally 블록은 심지어 try 블록 내에서 return이나 throw가 실행되더라도 반드시 실행됩니다. 이는 리소스 누수를 방지하는 데 매우 중요합니다.

6. 사용자 정의 예외 클래스

특정 상황에 대한 커스텀 예외를 만들고 싶다면, Exception 클래스를 상속받아 새로운 예외 클래스를 정의할 수 있습니다.
public class CustomException : Exception { public CustomException(string message) : base(message) { } } try { throw new CustomException("사용자 정의 예외 발생"); } catch (CustomException e) { Console.WriteLine($"커스텀 예외: {e.Message}"); }
C#
복사

7. 예외 필터링 (C# 6.0 이상)

C# 6.0부터는 when 키워드를 사용하여 예외를 필터링할 수 있습니다. 이를 통해 더 세밀한 예외 처리가 가능해졌습니다.
try { int number = int.Parse("abc"); } catch (FormatException e) when (e.Message.Contains("input string")) { Console.WriteLine("숫자 형식이 올바르지 않습니다."); }
C#
복사
이 기능은 특정 조건에 따라 예외를 다르게 처리해야 할 때 매우 유용합니다.

결론

예외 처리는 단순히 오류를 잡아내는 것 이상의 의미를 가집니다. 이는 프로그램의 안정성을 높이고, 예기치 못한 상황에 대해 우아하게 대처할 수 있게 해줍니다. C#의 예외 처리 방식을 통해 더 견고하고 신뢰할 수 있는 애플리케이션을 개발할 수 있습니다.

참고 자료

박상현, "이것이 C#이다", 한빛미디어, 2023