[C# 심층설명] 6장: 예외 처리와 디버깅: 예외의 개념과 처리 메커니즘

예외는 프로그램 실행 중에 발생하는 예기치 않은 이벤트 또는 오류 조건입니다. 입력 오류, 계산 오류, 자원 부족, 외부 환경 변화 등에 의해 발생할 수 있습니다. 객체 지향 프로그래밍 언어에서 예외는 일반적으로 프로그램 실행 중에 계속할 수 없는 오류로 인해 프로그램이 종료되거나 예상치 못한 결과가 발생하는 것을 의미합니다.
예외 처리의 중요성은 프로그램 안정성과 신뢰성을 향상시키는 능력에 있습니다. 실제 응용 시나리오에서 프로그램은 파일이 존재하지 않거나, 네트워크 연결이 중단되거나, 리소스가 고갈되는 등 다양한 비정상적인 상황에 직면할 수 있습니다. 적절한 예외 처리가 수행되지 않으면 이러한 예외로 인해 프로그램이 중단되거나 잘못된 결과가 생성되어 사용자 경험과 시스템 안정성에 심각한 영향을 미칠 수 있습니다. 합리적인 예외 처리를 통해 예외 발생 시 친숙한 오류 프롬프트 제공, 오류 기록, 예외 수정 시도, 프로그램 정상적으로 종료 등 해당 조치를 취할 수 있습니다. 이를 통해 프로그램의 비정상 종료를 방지하고, 프로그램의 내결함성을 높이고, 비정상 상황으로부터 시스템을 보호합니다. 프로그램 안정성과 신뢰성을 높이는 것 외에도 우수한 예외 처리는 문제를 더 잘 찾아 해결하는 데도 도움이 됩니다. 예외를 포착하고 자세한 오류 로깅을 수행함으로써 개발자는 오류 문제를 보다 쉽게 ​​해결하고 디버그할 수 있으므로 개발 효율성과 품질이 향상됩니다.

1. C# 예외 처리 메커니즘

1.1 예외 클래스의 상속 구조

C#에서는 예외 처리가 예외 클래스의 상속 구조를 통해 구현됩니다. 모든 예외 클래스는 예외 클래스 상속 구조의 기초가 되는 System.Exception 클래스에서 파생됩니다. System.Exception 클래스는 파생 예외 클래스에서 사용할 몇 가지 기본 속성과 메서드를 정의합니다.
C#의 예외 클래스 상속 구조는 다음과 같습니다.

  1. System.Exception: 모든 예외 클래스의 기본 클래스로 메시지, 스택 추적 등 예외에 대한 기본 정보를 포함합니다. 여기에는 두 가지 주요 파생 클래스가 있습니다.
    • System.SystemException: 시스템에서 정의한 예외 클래스의 기본 클래스이며 일반적으로 시스템에서 발생합니다.
    • System.ApplicationException: 일반적으로 애플리케이션에서 발생하는 사용자 정의 예외 클래스의 기본 클래스입니다.
  2. System.SystemException에서 파생된 몇 가지 일반적인 예외 클래스는 다음과 같습니다.
    • System.NullReferenceException: null 개체의 멤버에 액세스하려고 할 때 발생하는 예외입니다.
    • System.IndexOutOfRangeException: 배열이나 컬렉션에 존재하지 않는 인덱스에 액세스하려고 할 때 예외가 발생했습니다.
    • System.DividedByZeroException: 제수가 0일 때 발생하는 예외입니다.
    • System.ArithmeticException: 산술 연산 예외에 대한 기본 클래스입니다.
  3. System.ApplicationException에서 파생된 사용자 정의 예외 클래스:
    사용자는 필요에 따라 System.ApplicationException 클래스에서 파생하여 고유한 예외 유형을 정의할 수 있으므로 다양한 유형의 예외를 더 잘 구분할 수 있습니다.

예외 클래스의 상속 구조를 사용하여 개발자는 특정 예외 상황에 따라 다양한 유형의 예외를 포착하고 처리하도록 선택할 수 있습니다. 일반적으로 시스템에서 발생하는 예외는 System.SystemException 클래스에서 파생된 예외인 반면, 사용자 정의 예외는 일반적으로 System.ApplicationException 클래스에서 파생된 예외입니다. 예외를 포착할 때 예외 유형에 따라 로깅, 사용자에게 친숙한 오류 프롬프트 제공, 재시도 등 다양한 처리 로직을 수행할 수 있습니다. 예외 클래스의 상속 구조는 예외 처리를 더욱 유연하고 사용자 정의 가능하게 만들어 프로그램의 내결함성과 유지 관리성을 향상시키는 데 도움이 됩니다.

1.2 try-catch 블록

C#에서 try-catch 블록은 예외 처리를 위한 중요한 구성입니다. try-catch 블록을 사용하면 발생할 수 있는 예외를 포착하고 처리하는 코드를 작성할 수 있으므로 프로그램 충돌이나 예상치 못한 결과를 피할 수 있습니다. try-catch 블록의 기본 구문은 다음과 같습니다.

try
{
    
    
    // 可能会抛出异常的代码
}
catch (ExceptionType1 ex1)
{
    
    
    // 处理 ExceptionType1 类型的异常
}
catch (ExceptionType2 ex2)
{
    
    
    // 处理 ExceptionType2 类型的异常
}
// 可以有多个 catch 块,用于处理不同类型的异常
catch (Exception ex)
{
    
    
    // 处理其他类型的异常
}
finally
{
    
    
    // 可选的 finally 块,无论是否发生异常,都会执行其中的代码
}

try 블록에서는 예외를 발생시킬 수 있는 코드를 작성합니다. try 블록의 코드에서 예외가 발생하면 프로그램은 catch 블록으로 점프하고 예외 유형에 따라 해당 catch 블록을 일치시켜 예외를 처리합니다. 로깅, 사용자에게 친숙한 오류 프롬프트 제공 등과 같은 예외 처리 논리는 catch 블록에 작성될 수 있습니다. 예외 유형과 일치하는 catch 블록이 없으면 예외는 호출 스택을 통해 try-catch 블록으로 전달됩니다. 또는 일치하는 try-catch 블록이 없으면 프로그램이 중단됩니다. finally 블록은 선택 사항이며, try-catch 블록이 끝난 후에 실행되며, 예외 발생 여부에 관계없이 포함된 코드가 실행됩니다. finally 블록은 일반적으로 리소스를 해제하거나 파일 닫기, 데이터베이스 연결 등과 같은 일부 정리 작업을 수행하는 데 사용됩니다.
try-catch 블록을 사용하면 가능한 예외를 캡처하고 처리할 수 있어 프로그램의 내결함성과 안정성이 향상됩니다. 동시에 리소스 누출을 방지하기 위해 finally 블록에서 리소스의 올바른 릴리스도 보장할 수 있습니다. 전체적으로 try-catch 블록은 C#에서 예외를 처리하기 위한 핵심 도구 중 하나입니다.

1.3 throw 문

C#에서는 throw 문을 사용하여 예외를 수동으로 발생시킵니다. 프로그램이 throw 문까지 실행되면 현재 코드 블록의 실행을 즉시 종료하고 지정된 예외 개체를 호출 스택의 상위 try-catch 블록에 던지거나, 일치하는 try-catch 블록이 없는 경우 오류를 발생시킵니다. 프로그램 충돌.
throw 문의 기본 구문은 다음과 같습니다.

throw exception;

그 중 예외는 System.Exception 클래스에서 파생된 예외 개체입니다. throw 문을 통해 예외를 사용자 정의하고 예외를 발생시켜 호출자에게 예외가 발생했음을 알릴 수 있습니다.
예를 들어, 메소드에서 매개변수의 적법성을 확인하고 매개변수가 요구사항을 충족하지 않으면 ArgumentException을 발생시킬 수 있습니다.

public void Calculate(int value)
{
    
    
    if (value <= 0)
    {
    
    
        throw new ArgumentException("value must be greater than zero.", nameof(value));
    }

    // 其他计算逻辑
}

Calculate 메서드를 호출할 때 전달된 값이 0보다 작거나 같으면 ArgumentException이 발생하고 예외 메시지에 "값은 0보다 커야 합니다."라는 메시지가 표시되고 매개 변수 이름은 "value"입니다. 지정됩니다.
throw 문을 사용하면 예외 유형을 사용자 정의하고 필요할 때 예외를 발생시킬 수 있으므로 더 명확하고 의미 있는 예외 정보를 제공할 수 있습니다. 동시에 try-catch 블록과 throw 문의 합리적인 사용을 통해 예외 처리 메커니즘을 실현하여 프로그램의 안정성과 유지 관리성을 보장할 수 있습니다.

1.4 최종적으로 차단

C#에서 finally블록은 try-catch예외 발생 여부에 관계없이 실행되는 코드가 포함된 구조의 선택적 부분입니다. try블록에서 예외가 발생하는지 여부 에 관계없이 finally블록의 코드는 리소스의 올바른 해제 및 정리를 보장하기 위해 실행됩니다.
finally블록의 기본 구문은 다음과 같습니다.

try
{
    
    
    // 可能会抛出异常的代码
}
catch (ExceptionType1 ex1)
{
    
    
    // 处理 ExceptionType1 类型的异常
}
catch (ExceptionType2 ex2)
{
    
    
    // 处理 ExceptionType2 类型的异常
}
// 可以有多个 catch 块,用于处理不同类型的异常
catch (Exception ex)
{
    
    
    // 处理其他类型的异常
}
finally
{
    
    
    // 无论是否发生异常,都会执行其中的代码
}

finally블록은 일반적으로 리소스 정리, 파일 닫기, 데이터베이스 연결 또는 메모리 해제와 같은 작업을 수행하는 데 사용됩니다. try블록의 코드는 블록에서 예외가 발생했는지 여부에 관계없이 finally실행됩니다 . try이는 블록에서 예외가 발생하여 해당 catch블록 으로 점프 하더라도 finally블록의 코드가 계속 실행되어 리소스의 올바른 릴리스를 보장한다는 것을 의미합니다.
예를 들어, 파일 읽기 및 쓰기를 사용할 때 파일이 존재하지 않거나 액세스할 수 없는 등의 예외가 발생하는 경우 finally파일 스트림이 블록에서 올바르게 닫히는지 확인할 수 있습니다.

FileStream fileStream = null;
try
{
    
    
    fileStream = new FileStream("example.txt", FileMode.Open);
    // 其他文件读写操作
}
catch (IOException ex)
{
    
    
    // 处理文件读写异常
}
finally
{
    
    
    // 确保文件流被关闭
    if (fileStream != null)
    {
    
    
        fileStream.Close();
    }
}

이 예에서 블록의 코드는 try블록에서 예외가 발생했는지 여부에 관계없이 finally파일 스트림을 닫아 파일 리소스가 해제되도록 합니다.
finally블록은 예외 발생 여부에 관계없이 코드가 실행되고 필요한 정리가 수행되도록 하는 데 매우 유용한 구성입니다.

1.5 try-catch-finally 중첩

C#에서는 try-catch-finally블록을 중첩할 수 있습니다. 즉, 하나의 try블록 또는 catch블록이 다른 블록 내에 중첩될 수 있습니다 try-catch-finally. finally이러한 중첩 구조를 사용하면 다양한 수준의 예외를 처리할 수 있으며 최종 리소스 해제 및 정리는 가장 바깥쪽 블록에서 수행됩니다. 다음은 블록 중첩의 예
입니다 .try-catch-finally

try
{
    
    
    // 外层 try 块
    try
    {
    
    
        // 内层 try 块
        // 可能会抛出异常的代码
    }
    catch (ExceptionType1 ex1)
    {
    
    
        // 处理内层 try 块中抛出的 ExceptionType1 类型的异常
    }
    finally
    {
    
    
        // 内层 finally 块,用于内层资源的释放和清理
    }
}
catch (ExceptionType2 ex2)
{
    
    
    // 处理外层 try 块中抛出的 ExceptionType2 类型的异常
}
finally
{
    
    
    // 外层 finally 块,用于外层资源的释放和清理
}

이 중첩된 예에서는 try내부 블록에서 예외가 발생할 수 있으며, 예외가 발생하면 해당 catch블록으로 점프하여 처리한 후 finally내부 블록의 코드를 실행합니다. 그런 다음 제어는 외부 try-catch-finally블록으로 돌아가 실행되고 catch(일치하는 예외 유형이 있는 경우) 마지막으로 외부 finally블록이 실행됩니다.
중첩된 try-catch-finally블록을 사용하면 다양한 수준에서 예외를 처리하고 어떤 경우에도 리소스가 적절하게 해제되도록 보장하여 코드 신뢰성과 안정성을 유지할 수 있습니다. 실제 개발에서 중첩된 예외 처리 구조는 코드 예외 및 리소스 관리를 더 잘 관리하는 데 도움이 될 수 있습니다.

2. 예외 포착 및 처리

2.1 특정 유형의 예외 포착

C#에서는 catch블록을 사용하여 특정 유형의 예외를 포착하고 다양한 유형의 예외를 다르게 처리할 수 있습니다. 다음은 특정 유형의 예외를 포착하는 예입니다.

try
{
    
    
    // 可能会抛出异常的代码
    int[] arr = new int[5];
    int result = arr[10]; // 会抛出 IndexOutOfRangeException
}
catch (IndexOutOfRangeException ex)
{
    
    
    // 处理 IndexOutOfRangeException 类型的异常
    Console.WriteLine("发生了索引超出范围的异常:" + ex.Message);
}
catch (DivideByZeroException ex)
{
    
    
    // 处理 DivideByZeroException 类型的异常
    Console.WriteLine("发生了除以零的异常:" + ex.Message);
}
catch (Exception ex)
{
    
    
    // 处理其他类型的异常(如果上面的 catch 块没有匹配到异常)
    Console.WriteLine("发生了其他类型的异常:" + ex.Message);
}
finally
{
    
    
    // 最终的资源释放和清理
}

위의 예에서는 예외가 발생할 수 있는 코드가 먼저 실행을 시도하고, 예외가 발생하면 시스템은 catch해당 블록에서 발생한 예외의 유형과 일치하는 처리 로직을 찾습니다. 일치하는 catch블록이 발견되면 해당 블록의 코드가 실행되고 이어서 finally블록이 실행됩니다. 일치하는 블록이 발견되지 않으면 적합한 블록을 찾거나 기본 프로그램의 가장 바깥쪽 레벨에 도달할 catch때까지 호출 스택을 계속 검색합니다 . 특정 유형의 예외를 포착할 때 가장 구체적인 예외 유형을 첫 번째 블록에 배치하고 가장 일반적인 유형을 마지막 에 배치하는 것이 좋습니다 . 이렇게 하면 예외 처리의 우선순위가 정확하고 불필요한 오류 처리를 방지할 수 있습니다. 동시에 유형 블록에 처리되지 않은 예외를 처리하면 예기치 않은 예외가 발생해도 프로그램이 종료되지 않아 코드의 안정성과 신뢰성이 보장됩니다.catch
catchExceptionExceptioncatch

2.2 다중 캐치 블록

C#에서는 여러 catch블록을 사용하여 다양한 유형의 예외를 포착하고 다양한 유형의 예외를 다르게 처리할 수 있습니다. 여러 catch블록의 구문은 한 try블록 뒤에 여러 catch블록이 오는 형식입니다. catch블록은 서로 다른 예외 유형을 지정하며, 예외가 발생하면 시스템은 catch블록 순서대로 일치하는 예외 유형을 검색하고 catch일치하는 첫 번째 블록의 코드를 실행합니다. 다음은 여러 블록의 사용을
보여주는 예입니다 .catch

try
{
    
    
    // 可能会抛出异常的代码
    int[] arr = new int[5];
    int result = arr[10]; // 会抛出 IndexOutOfRangeException
}
catch (IndexOutOfRangeException ex)
{
    
    
    // 处理 IndexOutOfRangeException 类型的异常
    Console.WriteLine("发生了索引超出范围的异常:" + ex.Message);
}
catch (DivideByZeroException ex)
{
    
    
    // 处理 DivideByZeroException 类型的异常
    Console.WriteLine("发生了除以零的异常:" + ex.Message);
}
catch (Exception ex)
{
    
    
    // 处理其他类型的异常(如果上面的 catch 块没有匹配到异常)
    Console.WriteLine("发生了其他类型的异常:" + ex.Message);
}
finally
{
    
    
    // 最终的资源释放和清理
}

위의 예에서는 예외가 발생할 수 있는 코드가 먼저 실행을 시도하고, 예외가 발생하면 시스템은 catch블록 순서대로 일치하는 예외 유형을 찾습니다. 일치하는 catch블록이 발견되면 해당 블록의 코드가 실행되고 다른 catch블록은 건너뜁니다. 일치하는 블록이 발견되지 않으면 적합한 블록을 찾거나 기본 프로그램의 가장 바깥쪽 레벨에 도달할 catch때까지 호출 스택을 계속 검색합니다 . 여러 블록을 사용하면 다양한 유형의 예외를 더 자세히 처리할 수 있어 코드의 유연성과 가독성이 높아집니다. 예외 처리의 우선순위가 올바른지 확인하고 불필요한 오류 처리를 방지하려면 가장 구체적인 예외 유형을 첫 번째 블록에 배치하고 가장 일반적인 유형을 마지막 에 배치하는 것이 좋습니다 . 동시에 여러 블록을 사용하면 예외 처리 코드를 더 잘 구성하고 관리할 수 있어 코드 구조가 더 명확해지고 유지 관리가 쉬워집니다.catch
catchcatchExceptioncatch

2.3 기본 예외 유형 잡기

C#에서는 다양한 기본 예외 유형을 포착할 수 있습니다. 다음은 몇 가지 일반적인 기본 예외 유형과 그 용도입니다.

  1. System.Exception: 모든 예외 유형의 기본 클래스입니다. 일반적으로 우리는 이 예외를 직접 포착하지 않지만 해당 하위 클래스를 사용하여 특정 유형의 예외를 포착합니다.
  2. System.ArithmeticException: 0으로 나누기와 같은 산술 연산의 예외를 나타냅니다.
  3. System.IndexOutOfRangeException: 범위를 벗어난 배열 인덱스 예외를 나타냅니다.
  4. System.NullReferenceException: null 참조 개체의 멤버에 액세스하려고 할 때 발생하는 null 참조 예외를 나타냅니다.
  5. System.OutOfMemoryException: 필요한 메모리를 할당할 수 없을 때 발생하는 메모리 부족 예외를 나타냅니다.
  6. System.DivideByZeroException: 나누기 또는 모듈로 연산의 분모가 0일 때 발생하는 0으로 나누기 예외를 나타냅니다.
  7. System.StackOverflowException: 일반적으로 재귀 호출 중에 발생하는 스택 오버플로 예외를 나타냅니다.
  8. System.IO.IOException: 파일 및 스트림의 읽기 및 쓰기 작업 오류를 처리하는 데 사용되는 입력 및 출력 예외를 나타냅니다.
  9. System.FormatException: 문자열이 다른 유형으로 변환될 때 일반적으로 발생하는 형식 지정 예외를 나타냅니다.
  10. System.ArgumentException: 일반적으로 잘못된 매개변수 값이 전달될 때 발생하는 매개변수 예외를 나타냅니다.
  11. System.NotSupportedException: 지원되지 않는 메서드나 함수가 호출될 때 발생하는 지원되지 않는 작업 예외를 나타냅니다.

위에 나열된 기본 예외 유형 외에도 C#에서 포착할 수 있는 다른 예외 유형이 많이 있습니다. 코드를 작성할 때 특정 상황에 따라 포착할 적절한 예외 유형을 선택해야 예외를 더 잘 처리하고 오류에서 복구할 수 있습니다. 동시에 특정 애플리케이션 논리 오류를 나타내도록 예외 유형을 사용자 정의하여 코드 가독성과 유지 관리성을 높일 수도 있습니다.

2.4 포착되지 않은 예외의 결과

예외 유형과 발생 위치에 따라 포착되지 않은 예외로 인해 프로그램이 예기치 않게 종료되고 불안정해질 수 있습니다. 포착되지 않은 예외로 인해 발생할 수 있는 몇 가지 결과는 다음과 같습니다.

  1. 프로그램 충돌: 포착되지 않은 예외로 인해 프로그램이 충돌하여 콘솔이나 로그에 오류 메시지가 표시되면서 실행이 종료될 수 있습니다. 이로 인해 사용자 경험이 저하되고 데이터 손실이나 파일 손상이 발생할 수도 있습니다.
  2. 데이터 손실: 예외가 발생했을 때 예외를 올바르게 처리하지 않으면 저장하지 않은 데이터가 손실될 수 있습니다. 예를 들어, 파일 읽기 및 쓰기 작업에서 예외가 발생했지만 올바르게 처리되지 않은 경우 기록된 파일 내용이 불완전하거나 손상될 수 있습니다.
  3. 메모리 누수: 일부 예외로 인해 리소스가 올바르게 해제되지 않아 메모리 누수가 발생할 수 있습니다. 메모리 누수가 반복적으로 발생하면 결국 프로그램 실행 속도가 느려지거나 충돌이 발생할 수 있습니다.
  4. 불안정성: 포착되지 않은 예외는 프로그램 불안정성을 초래하여 예측 및 유지 관리를 어렵게 만들 수 있습니다. 처리되지 않은 예외는 프로그램의 여러 부분에서 반복되어 추적 및 수정이 어려울 수 있습니다.
  5. 보안 문제: 해커가 처리되지 않은 예외를 악용하여 보안 허점을 일으킬 수 있습니다. 해커는 예외를 사용하여 민감한 정보를 얻거나 무단 작업을 수행할 수 있습니다.

포착되지 않은 예외의 결과를 방지하려면 개발자는 프로그램에서 예외 처리 메커니즘을 적절하게 사용해야 합니다. 예외를 포착하고 처리함으로써 프로그램 흐름을 더 잘 제어하고 오류 조건을 처리하기 위한 적절한 조치를 취할 수 있습니다. 동시에 문제가 발생할 경우 조사하고 해결하기 위해 로그 시스템을 사용하여 비정상적인 정보를 기록하는 것이 좋습니다. 예외를 합리적으로 처리하면 프로그램의 안정성과 신뢰성이 향상됩니다.

3. 사용자 정의 예외

3.1 사용자 정의 예외 클래스 생성

C#에서는 사용자 지정 예외 클래스를 만드는 것이 매우 간단합니다. Exception 클래스를 확장하여 고유한 예외 클래스를 정의할 수 있습니다. 다음은 사용자 정의 예외 클래스를 생성하는 방법을 보여주는 샘플 코드입니다.

using System;

// 自定义异常类
public class MyCustomException : Exception
{
    
    
    // 构造函数
    public MyCustomException()
    {
    
    
    }

    // 带有异常消息的构造函数
    public MyCustomException(string message)
        : base(message)
    {
    
    
    }

    // 带有异常消息和内部异常的构造函数
    public MyCustomException(string message, Exception innerException)
        : base(message, innerException)
    {
    
    
    }
}

// 使用自定义异常类的示例
public class Program
{
    
    
    public static void Main()
    {
    
    
        try
        {
    
    
            // 抛出自定义异常
            throw new MyCustomException("这是一个自定义异常");
        }
        catch (MyCustomException ex)
        {
    
    
            // 捕获并处理自定义异常
            Console.WriteLine("捕获到自定义异常:" + ex.Message);
        }
        catch (Exception ex)
        {
    
    
            // 捕获其他异常
            Console.WriteLine("捕获到异常:" + ex.Message);
        }
    }
}

위 코드에서는 MyCustomExceptionC#의 Exception 클래스를 상속하는 사용자 지정 예외 클래스를 정의했습니다. throw그런 다음 키워드를 사용하여 Main 메서드에서 사용자 지정 예외를 발생시키고 catch블록에서 이 사용자 지정 예외를 포착하고 처리합니다.
예외 클래스를 사용자 정의함으로써 비즈니스 요구 사항과 예외 유형을 기반으로 보다 의미 있는 예외를 생성하고 프로그램에서 발생하는 오류 조건을 더 잘 처리하고 식별할 수 있습니다. 이렇게 하면 코드가 더 명확해지고 유지 관리가 쉬워지며 프로그램의 가독성과 신뢰성이 향상됩니다.

3.2 사용자 정의 예외 발생

C#에서는 사용자 지정 예외 클래스를 만들어 사용자 지정 예외를 발생시킬 수 있습니다. 먼저 Exception 클래스에서 상속된 사용자 정의 예외 클래스를 정의한 다음 키워드를 사용하여 throw사용자 정의 예외를 발생시켜야 합니다. 다음은 사용자 정의 예외를 발생시키는 방법을 보여주는 샘플 코드입니다.

using System;

// 自定义异常类
public class MyCustomException : Exception
{
    
    
    // 构造函数
    public MyCustomException()
    {
    
    
    }

    // 带有异常消息的构造函数
    public MyCustomException(string message)
        : base(message)
    {
    
    
    }

    // 带有异常消息和内部异常的构造函数
    public MyCustomException(string message, Exception innerException)
        : base(message, innerException)
    {
    
    
    }
}

// 使用自定义异常类的示例
public class Program
{
    
    
    public static void Main()
    {
    
    
        try
        {
    
    
            // 模拟一个条件,如果满足,则抛出自定义异常
            bool condition = true;
            if (condition)
            {
    
    
                // 抛出自定义异常
                throw new MyCustomException("这是一个自定义异常");
            }
            else
            {
    
    
                Console.WriteLine("条件不满足,没有抛出异常。");
            }
        }
        catch (MyCustomException ex)
        {
    
    
            // 捕获并处理自定义异常
            Console.WriteLine("捕获到自定义异常:" + ex.Message);
        }
        catch (Exception ex)
        {
    
    
            // 捕获其他异常
            Console.WriteLine("捕获到异常:" + ex.Message);
        }
    }
}

위 코드에서는 MyCustomExceptionC#의 Exception 클래스를 상속하는 사용자 지정 예외 클래스를 정의했습니다. 그런 다음 키워드를 사용하여 Main 메서드에서 throw사용자 지정 예외를 발생시킵니다 .
실제 응용 프로그램에서는 특정 조건이 충족되면 throw키워드를 통해 사용자 정의 예외를 발생시켜 적절한 예외 처리를 위해 프로그램에서 예외를 적극적으로 발생시킬 수 있습니다. 이를 통해 코드를 더욱 유연하고 안정적으로 만들 수 있으며 더 많은 예외 정보를 제공할 수 있어 디버깅 및 문제 해결에 편리합니다.

3.3 사용자 정의 예외 캡처 및 처리

C#에서 사용자 지정 예외를 포착하고 처리하는 것은 기본 제공 예외를 포착하는 것과 매우 유사합니다. 코드에서 사용자 정의 예외를 발생시키는 데 사용하면 블록을 통해 이러한 사용자 정의 예외를 포착하고 처리 throw할 수 있습니다 . try-catch다음은 사용자 정의 예외를 포착하고 처리하는 방법을 보여주는 샘플 코드입니다.

using System;

// 自定义异常类
public class MyCustomException : Exception
{
    
    
    // 构造函数
    public MyCustomException()
    {
    
    
    }

    // 带有异常消息的构造函数
    public MyCustomException(string message)
        : base(message)
    {
    
    
    }

    // 带有异常消息和内部异常的构造函数
    public MyCustomException(string message, Exception innerException)
        : base(message, innerException)
    {
    
    
    }
}

// 使用自定义异常类的示例
public class Program
{
    
    
    public static void Main()
    {
    
    
        try
        {
    
    
            // 模拟一个条件,如果满足,则抛出自定义异常
            bool condition = true;
            if (condition)
            {
    
    
                // 抛出自定义异常
                throw new MyCustomException("这是一个自定义异常");
            }
            else
            {
    
    
                Console.WriteLine("条件不满足,没有抛出异常。");
            }
        }
        catch (MyCustomException ex)
        {
    
    
            // 捕获并处理自定义异常
            Console.WriteLine("捕获到自定义异常:" + ex.Message);
        }
        catch (Exception ex)
        {
    
    
            // 捕获其他异常
            Console.WriteLine("捕获到异常:" + ex.Message);
        }
    }
}

위의 코드에서는 MyCustomException사용자 정의 예외를 발생시키는 데 사용되는 사용자 정의 예외 클래스를 정의합니다 throw. 이 메서드 에서는 발생할 수 있는 예외를 포착하기 위해 블록을 Main사용합니다 . try-catch조건이 충족되면 사용자 정의 예외가 포착되어 처리되고 예외 정보가 인쇄됩니다. 조건이 충족되지 않으면 예외가 발생하지 않으며 해당 프롬프트 정보가 직접 출력됩니다.

4. 예외 체인

4.1 InnerException 속성

C#에서 속성 은 현재 예외를 발생시킨 내부 예외(즉, 중첩 예외)를 가져오거나 설정하는 데 사용되는 클래스의 멤버 InnerException입니다 . Exception다른 예외에 의해 예외가 트리거되면 InnerException해당 특성을 사용하여 외부 예외에 대한 세부 정보를 얻을 수 있으며 이는 디버깅 및 문제 해결에 매우 유용합니다.
InnerException속성의 유형은 클래스에서 상속되는 System.Exception모든 예외 개체를 포함할 수 있음을 의미합니다 . Exception현재 예외가 다른 예외에 의해 발생한 경우 InnerException속성에는 이 외부 예외 개체가 포함됩니다. 현재 예외가 루트 예외인 경우(즉, 다른 예외가 발생하지 않은 경우) 속성은 InnerException입니다 null. 다음은 C#에서 특성을 사용하는 방법을 보여주는 샘플 코드입니다 InnerException.

using System;

public class Program
{
    
    
    public static void Main()
    {
    
    
        try
        {
    
    
            // 在外部方法中抛出异常
            OuterMethod();
        }
        catch (Exception ex)
        {
    
    
            // 捕获异常,并获取内部异常
            if (ex.InnerException != null)
            {
    
    
                Console.WriteLine("捕获到外部异常:" + ex.Message);
                Console.WriteLine("外部异常的类型:" + ex.GetType().FullName);
                Console.WriteLine("内部异常的消息:" + ex.InnerException.Message);
                Console.WriteLine("内部异常的类型:" + ex.InnerException.GetType().FullName);
            }
            else
            {
    
    
                Console.WriteLine("捕获到根异常:" + ex.Message);
                Console.WriteLine("根异常的类型:" + ex.GetType().FullName);
            }
        }
    }

    public static void OuterMethod()
    {
    
    
        try
        {
    
    
            // 在内部方法中抛出异常
            InnerMethod();
        }
        catch (Exception ex)
        {
    
    
            // 将内部异常包装并抛出外部异常
            throw new Exception("这是一个外部异常", ex);
        }
    }

    public static void InnerMethod()
    {
    
    
        // 抛出内部异常
        throw new Exception("这是一个内部异常");
    }
}

위 코드에서는 , 및 의 세 가지 메소드를 InnerMethod()정의 OuterMethod()했습니다 Main(). InnerMethod()내부 예외가 메서드에서 발생하고, 그 예외가 메서드에서 포착되어 외부 OuterMethod()예외로 래핑되어 발생됩니다. 이 메서드 에서는 Main()외부 예외를 포착하고 InnerException속성을 사용하여 내부 예외에 대한 정보를 가져옵니다. 출력에는 외부 예외의 메시지 및 유형과 내부 예외의 메시지 및 유형이 표시됩니다.

4.2 예외 체인 구축

C#에서는 InnerException특성을 사용하여 예외 체인을 구축하고 다른 예외에 예외를 중첩하여 예외 체인을 형성할 수 있습니다. 이는 여러 예외 계층을 처리하거나 외부 예외를 포착하는 동안 내부 예외를 래핑할 때 유용합니다.

다음은 예외 체인을 구축하는 방법을 보여주는 샘플 코드입니다.

using System;

public class Program
{
    
    
    public static void Main()
    {
    
    
        try
        {
    
    
            // 在外部方法中抛出异常
            OuterMethod();
        }
        catch (Exception ex)
        {
    
    
            // 捕获异常,并获取内部异常链
            PrintExceptionChain(ex);
        }
    }

    public static void OuterMethod()
    {
    
    
        try
        {
    
    
            // 在内部方法中抛出异常
            InnerMethod();
        }
        catch (Exception ex)
        {
    
    
            // 将内部异常包装并抛出外部异常
            throw new Exception("这是一个外部异常", ex);
        }
    }

    public static void InnerMethod()
    {
    
    
        // 抛出内部异常
        throw new Exception("这是一个内部异常");
    }

    public static void PrintExceptionChain(Exception ex)
    {
    
    
        // 打印异常链
        Console.WriteLine("异常链:");
        while (ex != null)
        {
    
    
            Console.WriteLine("异常消息:" + ex.Message);
            Console.WriteLine("异常类型:" + ex.GetType().FullName);
            ex = ex.InnerException;
        }
    }
}

위의 코드에서는 InnerMethod(), OuterMethod()Main()도우미 메서드의 세 가지 메서드를 정의합니다 PrintExceptionChain(). InnerMethod()내부 예외가 메서드에서 발생하고, 그 예외가 메서드에서 포착되어 외부 OuterMethod()예외로 래핑되어 발생됩니다. Main()메소드 에서 우리는 이 외부 예외를 포착하고 PrintExceptionChain()메소드를 사용하여 예외 체인을 인쇄합니다. 코드를 실행한 후에는 예외 체인에 내부 예외와 외부 예외에 대한 세부 정보가 포함되어 있음을 확인할 수 있습니다.

5. 모범 사례 및 예방 조치

예외 처리 사용 시 몇 가지 모범 사례와 고려 사항은 다음과 같습니다.

  1. 예외 상황에만 예외 처리를 사용하십시오 . 예외 처리는 예상치 못한 오류 조건을 처리하는 데 사용해야 하며 프로그램의 정상적인 흐름을 제어하는 ​​데 사용해서는 안 됩니다. 예외 처리를 과도하게 사용하면 성능에 영향을 줄 수 있으므로 정상적인 흐름 중에 예외를 던지고 잡는 것은 최대한 피해야 합니다.
  2. 특정 예외 유형 사용 : 일반 유형을 사용하는 대신 특정 예외 유형을 사용하여 특정 오류를 포착해 보세요 Exception. 이를 통해 다양한 유형의 예외를 더욱 정확하게 식별하고 처리할 수 있어 코드 가독성과 유지 관리성이 향상됩니다.
  3. 예외를 처리하는 것이 합리적이어야 합니다 . 예외를 포착한 후에는 로깅, 사용자에게 오류 메시지 표시, 트랜잭션 롤백 등 예외를 처리하기 위한 적절한 조치를 취해야 합니다. 단순히 예외를 무시하거나 아무 작업도 수행하지 않으면 디버깅하기 어려운 문제가 발생할 수 있습니다.
  4. 빈 캐치 블록 방지 : 빈 catch블록을 사용하지 마세요. 빈 블록을 사용하면 예외가 무시되어 문제를 찾아 수정하기가 어려워집니다. 적합한 처리 논리가 없는 경우 예외가 상위 계층에 계속 발생하도록 허용하거나 최소한 로그를 기록하는 것을 고려할 수 있습니다.
  5. 루프에서 예외 포착 방지 : 루프에서 예외를 포착하면 성능 문제가 발생할 수 있습니다. 가능하다면 루프 외부에서 예외를 처리하거나 루프 내부에서 조건을 사용하여 예외를 방지하세요.
  6. finally 블록을 사용하여 리소스 해제 : try블록 내 리소스(예: 파일, 데이터베이스 연결 등)를 열면 finally해당 블록 내에서 해당 리소스가 해제되는 지 확인해야 하며, 예외가 발생합니다.
  7. 적시에 예외 잡기 : 외부 자원에 접근할 때의 예외 처리(파일 읽기 및 쓰기, 네트워크 요청 등)나 예외가 발생할 수 있는 작업 등 예외를 적시에 포착하고 처리해야 합니다.
  8. 사용자 정의 예외 클래스 사용 : 경우에 따라 특정 오류 조건을 표현하고 예외의 가독성과 유지 관리성을 향상시키기 위해 사용자 정의 예외 클래스를 정의해야 할 수도 있습니다.
  9. 정기적으로 예외 처리 코드 확인 : 예외 처리 코드는 코드가 수정됨에 따라 변경될 수 있으므로 예외 처리 코드가 여전히 유효한지 정기적으로 확인하고 유지 관리해야 합니다.
  10. 적절한 수준에서 예외 처리 : 예외는 적절한 수준에서 처리되어야 합니다. 비즈니스 관련 예외는 비즈니스 논리 계층에서 처리되는 반면, 시스템 오류나 처리되지 않은 예외와 같은 보다 일반적인 예외는 상위 계층에서 처리됩니다.

6. 요약

이 문서에서는 C#에서 예외 처리의 중요성과 메커니즘을 자세히 소개합니다. 예외란 프로그램 실행 중에 발생하는 오류나 비정상적인 상황을 말하며, 프로그램의 견고성과 안정성에 중요한 역할을 합니다.
이 기사에서는 먼저 예외의 개념과 예외 클래스의 상속 구조를 설명하고, 다양한 유형의 예외를 더 잘 캡처하고 처리하기 위해 Exception 클래스에서 상속하여 사용자 정의 예외 클래스를 만듭니다. 그런 다음 이 기사에서는 예외를 포착하고 이를 catch 블록에서 처리하여 프로그램이 계속 실행되거나 적절한 조치를 취할 수 있도록 하는 try-catch 블록의 사용을 소개합니다.
예외 처리에 대한 모범 사례 측면에서 이 문서에서는 좋은 오류 메시지 출력 및 finally 블록을 사용하여 리소스를 해제하는 등의 고려 사항을 강조합니다. 또한 예외 체인을 구축하고 InnerException 속성을 사용하면 예외를 더 잘 추적하고 처리할 수 있습니다.

추천

출처blog.csdn.net/gangzhucoll/article/details/131820787