예외 처리 문 - throw
, try-catch
, try-finally
및 try-catch-finally
예외를 처리하려면 throw
및 try
문을 사용합니다. 예외를 throw하려면 throw
문을 사용합니다. 코드 블록 실행 중에 발생할 수 있는 예외를 catch하고 처리하려면 try
문을 사용합니다.
throw
문
throw
문은 예외를 throw합니다.
if (shapeAmount <= 0)
{
throw new ArgumentOutOfRangeException(nameof(shapeAmount), "Amount of shapes must be positive.");
}
throw e;
문에서 식 e
의 결과는 암시적으로 System.Exception으로 변환 가능해야 합니다.
기본 제공된 예외 클래스(예: ArgumentOutOfRangeException 또는 InvalidOperationException)를 사용할 수 있습니다. .NET은 특정 조건에서 예외를 throw하는 다음 도우미 메서드(ArgumentNullException.ThrowIfNull 및 ArgumentException.ThrowIfNullOrEmpty)도 제공합니다. System.Exception에서 파생되는 고유한 예외 클래스를 정의할 수도 있습니다. 자세한 내용은 예외 만들기 및 throw를 참조하세요.
catch
블록 내에서 throw;
문을 사용하여 catch
블록에서 처리되는 예외를 다시 throw할 수 있습니다.
try
{
ProcessShapes(shapeAmount);
}
catch (Exception e)
{
LogError(e, "Shape processing failed.");
throw;
}
참고 항목
throw;
는 Exception.StackTrace 속성에 저장된 예외의 원래 스택 추적을 유지합니다. 이와 반대로 throw e;
은 e
의 StackTrace 속성을 업데이트합니다.
예외가 throw되면 CLR(공용 언어 런타임)은 이 예외를 처리할 수 있는 catch
블록을 찾습니다. 현재 실행된 메서드에 이러한 catch
블록이 포함되어 있지 않으면 CLR은 현재 메서드를 호출한 메서드를 살펴보는 등 호출 스택을 살펴봅니다. catch
블록이 발견되지 않으면 CLR은 실행 스레드를 종료합니다. 자세한 내용은 C# 언어 사양의 예외가 처리되는 방법 섹션을 참조하세요.
throw
식
throw
를 식으로 사용할 수도 있습니다. 이는 다음과 같은 여러 경우에 편리할 수 있습니다.
조건 연산자. 다음 예제는 전달된 배열
args
이 비어 있을 때throw
표현식을 사용하여 ArgumentException를 반환하는 예제입니다:string first = args.Length >= 1 ? args[0] : throw new ArgumentException("Please supply at least one argument.");
Null 병합 연산자. 다음 예제는
throw
표현식을 사용하여 프로퍼티에 할당할 문자열이null
일 때 ArgumentNullException를 반환하는 예제입니다:public string Name { get => name; set => name = value ?? throw new ArgumentNullException(paramName: nameof(value), message: "Name cannot be null"); }
식 본문 람다 또는 메서드. 다음 예에서는
throw
식을 사용하여 InvalidCastException을 throw하여 DateTime 값으로의 변환이 지원되지 않음을 나타냅니다.DateTime ToDateTime(IFormatProvider provider) => throw new InvalidCastException("Conversion to a DateTime is not supported.");
try
문
다음 형식 중 하나로 try
문을 사용할 수 있습니다. try-catch
- try
블록 내에서 코드를 실행하는 동안 발생할 수 있는 예외를 처리합니다. try-finally
- 제어가 try
블록을 떠날 때 실행되는 코드를 지정합니다. try-catch-finally
- 앞의 두 가지 형식을 결합한 형태입니다.
try-catch
문
코드 블록 실행 중에 발생할 수 있는 예외를 처리하려면 try-catch
문을 사용합니다. try
블록 내에 예외가 발생할 수 있는 코드를 배치합니다. catch 절를 사용하여 해당 catch
블록에서 처리하려는 예외의 기본 유형을 지정합니다:
try
{
var result = Process(-3, 4);
Console.WriteLine($"Processing succeeded: {result}");
}
catch (ArgumentException e)
{
Console.WriteLine($"Processing failed: {e.Message}");
}
여러 catch 절을 제공할 수 있습니다.
try
{
var result = await ProcessAsync(-3, 4, cancellationToken);
Console.WriteLine($"Processing succeeded: {result}");
}
catch (ArgumentException e)
{
Console.WriteLine($"Processing failed: {e.Message}");
}
catch (OperationCanceledException)
{
Console.WriteLine("Processing is cancelled.");
}
예외가 발생하면 catch 절은 지정된 순서에 따라 위에서 아래로 검사됩니다. throw된 예외에 대해 최대 하나의 catch
블록만 실행됩니다. 앞의 예에서도 볼 수 있듯이 예외 변수 선언을 생략하고 catch 절에 예외 형식만 지정할 수 있습니다. 지정된 예외 형식이 없는 catch 절은 모든 예외와 일치하며, 있는 경우 마지막 catch 절이어야 합니다.
발생한 예외를 다시 throw하려면 다음 예와 같이 throw
문을 사용합니다.
try
{
var result = Process(-3, 4);
Console.WriteLine($"Processing succeeded: {result}");
}
catch (Exception e)
{
LogError(e, "Processing failed.");
throw;
}
참고 항목
throw;
는 Exception.StackTrace 속성에 저장된 예외의 원래 스택 추적을 유지합니다. 이와 반대로 throw e;
은 e
의 StackTrace 속성을 업데이트합니다.
when
예외 필터
예외 형식과 함께 예외를 추가로 검사하고 해당 catch
블록이 해당 예외를 처리하는지 결정하는 예외 필터를 지정할 수도 있습니다. 예외 필터는 다음 예와 같이 when
키워드 뒤에 오는 부울 식입니다.
try
{
var result = Process(-3, 4);
Console.WriteLine($"Processing succeeded: {result}");
}
catch (Exception e) when (e is ArgumentException || e is DivideByZeroException)
{
Console.WriteLine($"Processing failed: {e.Message}");
}
앞의 예에서는 예외 필터를 사용하여 지정된 두 가지 형식의 예외를 처리하는 단일 catch
블록을 제공합니다.
예외 필터로 구분되는 경우 동일한 예외 형식에 대해 여러 개의 catch
절을 제공할 수 있습니다. 해당 조항 중 하나에는 예외 필터가 없을 수 있습니다. 그러한 절이 존재하는 경우 해당 예외 형식을 지정하는 절 중 마지막 절이어야 합니다.
catch
절에 예외 필터가 있는 경우 뒤에 나타나는 catch
절의 예외 형식과 동일하거나 그보다 적게 파생된 예외 형식을 지정할 수 있습니다. 예를 들어, 예외 필터가 있는 경우 catch (Exception e)
절이 마지막 절일 필요는 없습니다.
비동기 및 반복기 메서드의 예외
비동기 함수에서 예외가 발생하면 다음 예와 같이 함수 결과를 대기할 때 예외가 함수 호출자에게 전파됩니다.
public static async Task Run()
{
try
{
Task<int> processing = ProcessAsync(-1);
Console.WriteLine("Launched processing.");
int result = await processing;
Console.WriteLine($"Result: {result}.");
}
catch (ArgumentException e)
{
Console.WriteLine($"Processing failed: {e.Message}");
}
// Output:
// Launched processing.
// Processing failed: Input must be non-negative. (Parameter 'input')
}
private static async Task<int> ProcessAsync(int input)
{
if (input < 0)
{
throw new ArgumentOutOfRangeException(nameof(input), "Input must be non-negative.");
}
await Task.Delay(500);
return input;
}
반복기 메서드에서 예외가 발생하면 반복기가 다음 요소로 이동할 때만 호출자에게 전파됩니다.
try-finally
문
try-finally
문에서 제어가 try
블록을 떠날 때 finally
블록이 실행됩니다. 다음의 결과로 제어가 try
블록을 떠날 수 있습니다.
- 일반 실행,
- 점프 문(즉,
return
,break
,continue
또는goto
) 실행 또는 try
블록 외부로 예외 전파.
다음 예에서는 제어가 메서드를 떠나기 전에 finally
블록을 사용하여 개체의 상태를 다시 설정합니다.
public async Task HandleRequest(int itemId, CancellationToken ct)
{
Busy = true;
try
{
await ProcessAsync(itemId, ct);
}
finally
{
Busy = false;
}
}
finally
블록을 사용하여 try
블록에 사용된 할당된 리소스를 정리할 수도 있습니다.
참고 항목
리소스 형식이 IDisposable 또는 IAsyncDisposable 인터페이스를 구현하는 경우 using
문을 고려합니다. using
문은 제어가 using
문을 벗어날 때 획득한 리소스가 삭제되도록 보장합니다. 컴파일러는 using
문을 try-finally
문으로 변환합니다.
finally
블록의 실행은 운영 체제에서 예외 해제 작업을 트리거하도록 선택하는지 여부에 따라 달라집니다. finally
블록이 실행되지 않는 유일한 경우는 프로그램이 즉시 종료되는 것입니다. 예를 들어, 이러한 종료는 Environment.FailFast 호출이나 OverflowException 또는 InvalidProgramException 예외로 인해 발생할 수 있습니다. 대부분의 운영 체제는 프로세스 중지 및 언로드의 일부로 합리적인 리소스 정리를 수행합니다.
try-catch-finally
문
try-catch-finally
문을 사용하여 try
블록 실행 중에 발생할 수 있는 예외를 처리하고 제어가 try
문을 벗어날 때 실행되어야 하는 코드를 지정합니다.
public async Task ProcessRequest(int itemId, CancellationToken ct)
{
Busy = true;
try
{
await ProcessAsync(itemId, ct);
}
catch (Exception e) when (e is not OperationCanceledException)
{
LogError(e, $"Failed to process request for item ID {itemId}.");
throw;
}
finally
{
Busy = false;
}
}
catch
블록에서 예외를 처리하는 경우 finally
블록은 해당 catch
블록 실행 후에 실행됩니다(catch
블록 실행 중에 다른 예외가 발생하더라도). catch
및 finally
블록에 대한 자세한 내용은 각각 try-catch
명령문 및 try-finally
명령문 섹션을 참조하세요.
C# 언어 사양
자세한 내용은 C# 언어 사양의 다음 섹션을 참조하세요.
참고 항목
.NET