서론
개발에서 오류는 피할 수 없는 현실입니다. 특히 다양한 외부 요인과 상호작용하는 복잡한 시스템에서는 더욱 그렇습니다. 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