예외 처리(Exception Handling)는 프로그램에서 예상치 못한 상황이 발생했을 때 이를 안전하게 처리하기 위한 메커니즘이다. C#에서는
trycatchfinallythrow키워드를 사용하여 예외 처리를 수행한다.
Finally 블록: C#에서는 finally 블록이 있어 예외가 발생하든 발생하지 않든 실행되는 코드를 지정할 수 있다. C++에서는 try와 catch만 사용된다.
예외 타입: C#에서는 모든 예외가 Exception 클래스로부터 파생된다. C++에서는 어떤 데이터 타입이든 예외로 던질 수 있다.
using 문: using 문은 스코프가 시작될 때 리소스를 할당하고, 스코프가 끝날 때 Dispose 메소드를 자동으로 호출한다. 이를 통해 프로그래머는 명시적으로 리소스를 해제할 필요가 없으며, 리소스 누수나 다른 문제를 방지할 수 있다.
using 문을 사용하면 try-finally 구문을 사용하는 것보다 코드가 간결해지고 가독성이 높아진다.
using declaration: C# 8.0부터는 using 문을 더 간결하게 작성할 수 있는 새로운 문법. 별도의 블록 {}을 작성할 필요 없이 using 키워드를 변수 선언 앞에 붙여서 해당 변수가 스코프를 벗어날 때 자동으로 Dispose 메소드가 호출되도록 할 수 있다.
try
{
int x = 10;
int y = 0;
int z = x / y; // DivideByZeroException
}
catch (DivideByZeroException e)
{
Console.WriteLine($"예외 발생: {e.Message}");
}
finally
{
Console.WriteLine("예외가 발생하든 안 하든 이 부분은 실행");
}
using (StreamReader reader = File.OpenText("file.txt"))
{
string line = reader.ReadLine();
Console.WriteLine(line);
}
// 여기서 Dispose()가 호출됨
if (File.Exists("file.txt"))
{
using var reader = File.OpenText("file.txt");
string line = reader.ReadLine();
Console.WriteLine(line);
// ...
} // 여기서 Dispose()가 호출됨
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 블록에서 이를 처리한다.
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를 표현식으로 사용 가능. 이를 통해 람다 식이나 조건 연산자 등에서도 예외를 발생시킬 수 있다.
try { ... }
catch (Exception ex)
{
// Log error
...
throw; // Rethrow same exception
}
간혹 catch 블록에서 예외를 잡은 후에 다시 쓰로우해야 하는 경우가 있다. 이 때는 throw; 구문을 사용하면 현재 잡힌 예외를 다시 쓰로우할 수 있다.
catch (WebException ex) when (ex.Status == WebExceptionStatus.Timeout)
{
Console.WriteLine ("Timeout");
}
catch 절에 when 키워드를 사용하면 특정 조건을 만족하는 경우에만 예외를 캐치할 수 있다. WebException이 타임아웃일 때만 예외를 캐치하고 있다.
try
{
... // Parse a DateTime from XML element data
}
catch (FormatException ex)
{
throw new XmlException ("Invalid DateTime", ex); // ex: InnerException
}
새로운 예외를 던질 때 원래의 예외를 InnerException으로 포함시킨다. 이를 통해 디버깅이 쉬워지고, 원래 예외의 정보를 잃지 않게 된다.
catch 블록을 사용 가능.