예외 처리(C# 프로그래밍 가이드)

try 블록은 C# 프로그래머가 예외의 영향을 받을 수 있는 코드를 분할하는 데 사용됩니다. 연결된 catch 블록은 결과 예외를 처리하는 데 사용됩니다. finally 블록에는 try 블록에서 할당되는 리소스 해제와 같이 try 블록에서 예외가 throw되는지 여부와 관계없이 실행되는 코드가 포함됩니다. try 블록에는 하나 이상의 연결된 catch 블록, finally 블록 또는 둘 다가 필요합니다.

다음 예제에서는 try-catch 문, try-finally 문 및 try-catch-finally 문을 보여 줍니다.

try
{
    // Code to try goes here.
}
catch (SomeSpecificException ex)
{
    // Code to handle the exception goes here.
    // Only catch exceptions that you know how to handle.
    // Never catch base class System.Exception without
    // rethrowing it at the end of the catch block.
}
try
{
    // Code to try goes here.
}
finally
{
    // Code to execute after the try block goes here.
}
try
{
    // Code to try goes here.
}
catch (SomeSpecificException ex)
{
    // Code to handle the exception goes here.
}
finally
{
    // Code to execute after the try (and possibly catch) blocks
    // goes here.
}

try 블록에 catch 또는 finally 블록이 없으면 컴파일러 오류가 발생합니다.

catch 블록

catch 블록에서는 catch할 예외의 형식을 지정할 수 있습니다. 형식 사양을 예외 필터라고 합니다. 예외 형식은 Exception에서 파생되어야 합니다. 일반적으로 Exception 블록에서 throw될 수 있는 모든 예외를 처리하는 방법을 알고 있거나 try 블록의 끝에 throw을 포함한 경우가 아니라면 catch를 예외 필터로 지정하지 마세요.

다른 예외 클래스를 사용하는 여러 catch 블록을 함께 연결할 수 있습니다. catch 블록은 코드의 위에서 아래로 계산되지만 throw되는 각 예외에 대해 하나의 catch 블록만 실행됩니다. throw된 예외의 정확한 형식이나 기본 클래스를 지정하는 첫 번째 catch 블록이 실행됩니다. catch 블록에서 일치하는 예외 클래스를 지정하지 않으면 catch 블록이 문에 있는 경우 어느 형식도 없는 블록이 선택됩니다. 먼저 가장 구체적인(즉, 최다 파생) 예외 클래스를 사용하여 catch 블록을 배치해야 합니다.

다음 조건을 충족하는 경우 예외를 catch합니다.

  • 예외가 throw되는 이유를 충분히 이해하고 있으면 FileNotFoundException 개체를 catch할 때 새 파일 이름을 입력하라는 메시지를 사용자에게 표시하는 경우처럼 구체적인 복구를 구현할 수 있습니다.
  • 보다 구체적인 새 예외를 생성하고 throw할 수 있습니다.
    int GetInt(int[] array, int index)
    {
        try
        {
            return array[index];
        }
        catch (IndexOutOfRangeException e)
        {
            throw new ArgumentOutOfRangeException(
                "Parameter index is out of range.", e);
        }
    }
    
  • 추가 처리를 위해 예외를 전달하기 전에 예외를 부분적으로 처리하려고 합니다. 다음 예제에서 catch 블록은 예외를 다시 throw하기 전에 오류 로그에 항목을 추가하는 데 사용됩니다.
    try
    {
        // Try to access a resource.
    }
    catch (UnauthorizedAccessException e)
    {
        // Call a custom error logging procedure.
        LogError(e);
        // Re-throw the error.
        throw;
    }
    

‘예외 필터’를 지정하여 catch 절에 부울 식을 추가할 수도 있습니다. 예외 필터는 해당 조건이 true인 경우에만 특정 catch 절이 일치함을 나타냅니다. 다음 예에서는 두 catch 절 모두 동일한 예외 클래스를 사용하지만 다른 오류 메시지를 만들기 위해 추가 조건을 확인합니다.

int GetInt(int[] array, int index)
{
    try
    {
        return array[index];
    }
    catch (IndexOutOfRangeException e) when (index < 0) 
    {
        throw new ArgumentOutOfRangeException(
            "Parameter index cannot be negative.", e);
    }
    catch (IndexOutOfRangeException e)
    {
        throw new ArgumentOutOfRangeException(
            "Parameter index cannot be greater than the array size.", e);
    }
}

항상 false를 반환하는 예외 필터를 사용하여 모든 예외를 검사하지만 처리하지는 않을 수 있습니다. 일반적인 용도는 예외를 기록하는 것입니다.

public class ExceptionFilter
{
    public static void Main()
    {
        try
        {
            string? s = null;
            Console.WriteLine(s.Length);
        }
        catch (Exception e) when (LogException(e))
        {
        }
        Console.WriteLine("Exception must have been handled");
    }

    private static bool LogException(Exception e)
    {
        Console.WriteLine($"\tIn the log routine. Caught {e.GetType()}");
        Console.WriteLine($"\tMessage: {e.Message}");
        return false;
    }
}

LogException 메서드는 항상 false를 반환하므로 이 예외 필터를 사용하는 catch 절 중 어느 것도 일치하지 않습니다. catch 절은 System.Exception을 사용하는 범용일 수 있으며 이후 절이 더 구체적인 예외 클래스를 처리할 수 있습니다.

Finally 블록

finally 블록에서는 try 블록에서 수행된 작업을 정리할 수 있습니다. finally 블록이 있는 경우 try 블록 및 일치하는 모든 catch 블록 다음에 마지막으로 실행됩니다. finally 블록은 예외가 throw되었는지 또는 예외 형식과 일치하는 catch 블록이 있는지와 관계없이 항상 실행됩니다.

finally 블록은 런타임의 가비지 수집기가 개체를 종료할 때까지 기다리지 않고 파일 스트림, 데이터베이스 연결, 그래픽 핸들 등의 리소스를 해제하는 데 사용됩니다.

다음 예제에서는 finally 블록을 사용하여 try 블록에서 연 파일을 닫습니다. 파일을 닫기 전에 파일 핸들의 상태를 확인해야 합니다. try 블록에서 파일을 열 수 없는 경우 파일 핸들은 값이 null이며 finally 블록은 파일을 닫지 않습니다. 대신 try 블록에서 파일을 연 경우 finally 블록에서 열려 있는 파일을 닫습니다.

FileStream? file = null;
FileInfo fileinfo = new System.IO.FileInfo("./file.txt");
try
{
    file = fileinfo.OpenWrite();
    file.WriteByte(0xF);
}
finally
{
    // Check for null because OpenWrite might have failed.
    file?.Close();
}

C# 언어 사양

자세한 내용은 C# 언어 사양예외try 문을 참조하세요. 언어 사양은 C# 구문 및 사용법에 대 한 신뢰할 수 있는 소스 됩니다.

참고 항목