예외 처리 Exception Handling

Gogi·2023년 9월 6일

C# 언어 기초 목록

목록 보기
17/29

예외 상황 발생 시 처리

예외 처리(Exception Handling)는 프로그램에서 예상치 못한 상황이 발생했을 때 이를 안전하게 처리하기 위한 메커니즘이다. C#에서는 try catch finally throw 키워드를 사용하여 예외 처리를 수행한다.


기본 개념 및 C++과의 차이점

  1. Finally 블록: C#에서는 finally 블록이 있어 예외가 발생하든 발생하지 않든 실행되는 코드를 지정할 수 있다. C++에서는 trycatch만 사용된다.

  2. 예외 타입: C#에서는 모든 예외가 Exception 클래스로부터 파생된다. C++에서는 어떤 데이터 타입이든 예외로 던질 수 있다.

  3. using 문: using 문은 스코프가 시작될 때 리소스를 할당하고, 스코프가 끝날 때 Dispose 메소드를 자동으로 호출한다. 이를 통해 프로그래머는 명시적으로 리소스를 해제할 필요가 없으며, 리소스 누수나 다른 문제를 방지할 수 있다.
    using 문을 사용하면 try-finally 구문을 사용하는 것보다 코드가 간결해지고 가독성이 높아진다.

  4. using declaration: C# 8.0부터는 using 문을 더 간결하게 작성할 수 있는 새로운 문법. 별도의 블록 {}을 작성할 필요 없이 using 키워드를 변수 선언 앞에 붙여서 해당 변수가 스코프를 벗어날 때 자동으로 Dispose 메소드가 호출되도록 할 수 있다.


사용 예시

1. 기본 문법들

- try-finally 문법

try
{
    int x = 10;
    int y = 0;
    int z = x / y;  // DivideByZeroException
}
catch (DivideByZeroException e)
{
    Console.WriteLine($"예외 발생: {e.Message}");
}
finally
{
    Console.WriteLine("예외가 발생하든 안 하든 이 부분은 실행");
}

- using 문법

using (StreamReader reader = File.OpenText("file.txt"))
{
    string line = reader.ReadLine();
    Console.WriteLine(line);
}  
// 여기서 Dispose()가 호출됨

- using declaration을 사용한 문법 (C# 8.0 이상)

if (File.Exists("file.txt"))
{
    using var reader = File.OpenText("file.txt");
    string line = reader.ReadLine();
    Console.WriteLine(line);
    // ...
}  // 여기서 Dispose()가 호출됨

2. C#에서 예외 처리와 관련된 다양한 방법들

- Throwing Exceptions

try { Display (null); }
catch (ArgumentNullException ex)
{
  Console.WriteLine ("Caught the exception");
}

void Display (string name)
{
  if (name == null)
    throw new ArgumentNullException (nameof (name));

  Console.WriteLine (name);
}

첫 번째 코드 블록에서는 ArgumentNullException을 명시적으로 쓰로우한다. Display 함수에서 name 파라미터가 null일 경우, ArgumentNullException이 쓰로우가 발생하고 catch 블록에서 이를 처리한다.

- throw 표현식

public string Foo() => throw new NotImplementedException();
string ProperCase (string value) =>
  value == null ? throw new ArgumentException ("value") :
  value == "" ? "" :
  char.ToUpper (value[0]) + value.Substring (1);

C# 7.0부터는 throw를 표현식으로 사용 가능. 이를 통해 람다 식이나 조건 연산자 등에서도 예외를 발생시킬 수 있다.

- Rethrowing an Exception

try {  ...  }
catch (Exception ex)
{
  // Log error
  ...
  throw; // Rethrow same exception
}

간혹 catch 블록에서 예외를 잡은 후에 다시 쓰로우해야 하는 경우가 있다. 이 때는 throw; 구문을 사용하면 현재 잡힌 예외를 다시 쓰로우할 수 있다.

- 조건부 예외 처리 Exception Filtering

catch (WebException ex) when (ex.Status == WebExceptionStatus.Timeout)
{
  Console.WriteLine ("Timeout");
}

catch 절에 when 키워드를 사용하면 특정 조건을 만족하는 경우에만 예외를 캐치할 수 있다. WebException이 타임아웃일 때만 예외를 캐치하고 있다.

- 내부 예외(Inner Exception)

try
{
  ... // Parse a DateTime from XML element data
}
catch (FormatException ex)
{
  throw new XmlException ("Invalid DateTime", ex); // ex: InnerException
}

새로운 예외를 던질 때 원래의 예외를 InnerException으로 포함시킨다. 이를 통해 디버깅이 쉬워지고, 원래 예외의 정보를 잃지 않게 된다.


용어 설명

  • Try 블록: 예외가 발생할 수 있는 코드를 포함하는 블록.
  • Catch 블록: 예외가 발생했을 때 실행되는 코드 블록. 여러 개의 catch 블록을 사용 가능.
  • Finally 블록: 예외 발생 여부와 관계없이 항상 실행되는 코드 블록.
  • Throw: 프로그래머가 명시적으로 예외를 발생시킬 때 사용하는 키워드.
profile
C, C++, C#, Unity

0개의 댓글