예외 처리 문 - throw, try-catch, try-finallytry-catch-finally

try 문을 사용하여 throw 예외를 처리합니다. throw 문을 사용하여 예외를 throw합니다. try 문을 사용하여 코드 블록을 실행하는 동안 발생할 수 있는 예외를 catch하고 처리합니다.

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은 특정 조건에서 ArgumentNullException.ThrowIfNull 예외를 throw하는 도우미 메서드인 및 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 수도 있습니다. 다음과 같은 여러 경우에 편리할 수 있습니다.

  • 조건 연산자. 다음 예제에서는 전달된 배열 argsthrow 비어 있을 ArgumentException 때 식을 사용하여 을 throw합니다.

    string first = args.Length >= 1 
        ? args[0]
        : throw new ArgumentException("Please supply at least one argument.");
    
  • Null 병합 연산자. 다음 예제에서는 식을 사용하여 throw 속성null에 할당할 문자열이 인 경우 을 throw ArgumentNullException 합니다.

    public string Name
    {
        get => name;
        set => name = value ??
            throw new ArgumentNullException(paramName: nameof(value), message: "Name cannot be null");
    }
    
  • 식 본문 람다 또는 메서드. 다음 예제에서는 식을 사용하여 throw 를 throw InvalidCastException 하여 값으로의 변환이 지원되지 않음을 DateTime 나타냅니다.

    DateTime ToDateTime(IFormatProvider provider) =>
             throw new InvalidCastException("Conversion to a DateTime is not supported.");
    

try

문은 trytry-catch 블록 내에서 try 코드를 실행하는 동안 발생할 수 있는 예외를 처리하고, 컨트롤이 블록을 떠날 try 때 실행되는 코드를 지정하고 try-catch-finally , try-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 절이어야 합니다.

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 블록이 해당 예외를 처리하는지 여부를 결정하는 예외 필터를 지정할 수도 있습니다. 예외 필터는 다음 예제와 같이 키워드(keyword) 따르는 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 컨트롤이 finally 블록을 벗어나면 블록이 try 실행됩니다. 의 결과로 컨트롤이 try 블록을 떠날 수 있습니다.

  • 일반 실행,
  • jump 문의 실행(즉, , returnbreak, continue또는 ) 또는 goto
  • 블록에서 예외 전파 try .

다음 예제에서는 블록을 사용하여 finally 컨트롤이 메서드를 벗어나기 전에 개체의 상태를 다시 설정합니다.

public async Task HandleRequest(int itemId, CancellationToken ct)
{
    Busy = true;

    try
    {
        await ProcessAsync(itemId, ct);
    }
    finally
    {
        Busy = false;
    }
}

블록을 사용하여 블록에 finally 사용되는 try 할당된 리소스를 클린 수도 있습니다.

참고

리소스 형식이 또는 IAsyncDisposable 인터페이스를 구현하는 IDisposable 경우 문을 고려합니다using. 문은 using 제어가 문을 떠날 using 때 획득한 리소스가 삭제되도록 합니다. 컴파일러는 문을 문으로 try-finally 변환합니다using.

거의 모든 경우에 블록이 finally 실행됩니다. 블록이 finally 실행되지 않는 유일한 경우는 프로그램의 즉각적인 종료와 관련이 있습니다. 예를 들어 이러한 종료는 호출 또는 OverflowException 또는 InvalidProgramException 예외로 Environment.FailFast 인해 발생할 수 있습니다. 대부분의 운영 체제는 프로세스 중지 및 언로드의 일부로 적절한 리소스 클린 수행합니다.

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 실행됩니다. 및 finally 블록에 대한 catch 자세한 내용은 문 및 try-finally 섹션을 각각 참조 try-catch 하세요.

C# 언어 사양

자세한 내용은 C# 언어 사양의 다음 섹션을 참조하세요.

참고 항목