C#

[C#]내부 예외 처리(Inner Exception)

DevStory 2022. 6. 26.

내부 예외(Inner Exception)

C#의 Exception 클래스의 InnerException은 예외 클래스의 프로퍼티입니다. InnerException 프로퍼티는 현재 예외를 발생시킨 예외를 반환합니다.

 

InnerException 프로퍼티에 대해 설명이 부족한 이유는 글로 설명하면, 오히려 이해가 안 될 수 있으므로 다음 예제를 통해 InnerException 프로퍼티가 어떻게 동작하는지 설명합니다.


중첩된 try~catch문

InnerException 프로퍼티를 설명하기 전에 중첩된 try~catch문에 대해 알아봅시다. 예외를 처리하는 try~catch문은 중첩될 수 있습니다. 다음 코드처럼 try문 내부에 또 다른 try~catch문이 존재할 수 있다는 의미입니다.

try  // 외부 try문
{
  try // 내부 try문
  {
    // ...
  }
  catch (Exception e) // 내부 catch문
  {
    // ...
  }
}
catch(Exception e) // 외부 catch문
{
  // ...
}

내부 try문에서 예외가 발생한 경우 내부 catch문이 실행됩니다. 그런데, 내부 catch문에서 예외 처리를 제대로 수행하지 못해서 또 다른 예외가 발생한다면?

 

다음 예제를 통해 내부 catch문에서 예외가 발생한 경우 어떻게 동작하는지 알아봅시다. 다음 예제는 콘솔에서 입력받은 두 개의 값을 변수 a와 b에 할당 후 변수 c를 a와 b로 나눈 값으로 할당합니다.

 

만약, 변수 b의 값을 0으로 할당하면 a를 0으로 나누게 되므로 DivideByZeroException이 발생하고 숫자가 아닌 문자열로 할당하면 숫자로 파싱 하는 과정에서 FormatException이 발생합니다.

 

 DivideByZeroException 또는 FormatException 예외가 발생하면 Log.txt라는 파일에 예외 내용을 기록(Write)합니다.

class Program
{
  static void Main(string[] args)
  {
    int a, b, c;

    try // 1. 외부 try문
    {
      try // 2. 중첩된 try문
      {
        a = int.Parse(Console.ReadLine());
        b = int.Parse(Console.ReadLine());
        c = a / b;
        Console.WriteLine("C VALUE = " + c);
      }
      catch (Exception e) // 3. 중첩된 catch문
      {
        Console.WriteLine("\n내부 catch문 실행");
        Console.WriteLine(e.Message + "\n");

        string filePath = @"C:\LogDirectory\Log.txt";
        StreamWriter sw = new StreamWriter(filePath);
        sw.Write(e.Message);
        sw.Close();
      }
    } 
    catch(Exception e) // 4. 외부 catch문
    {
      Console.WriteLine("\n외부 catch문 실행");
      Console.WriteLine(e.Message + "\n");
    }
  }
}

[실행 결과]

100
0

내부 catch 실행
Attempted to divide by zero.


외부 catch 실행
Could not find a part of the path 'C:\LogDirectory\Log.txt'.
  1. 100과 0을 입력합니다. 100은 0으로 나눌 수 없으므로 DivideByZeroException이 발생하고 내부 catch문이 실행됩니다.
  2. 내부 catch문에서 Log.txt 파일이 존재하지 않으므로 FileNotFoundException 예외가 발생하였고 외부 catch문이 실행됩니다.

 

그렇다면, 외부 catch문에서는 내부 catch문이 실행되었던 원인인 DivideByZeroExcption를 찾을 수 없는 걸까요? 그렇지 않습니다.

 

Exception 클래스의 InnerException 프로퍼티에는 원래 예외가 존재합니다.


InnerException 프로퍼티 예제

다음 예제는 내부 catch문과 외부 catch문을 수정하였습니다.

 

내부 catch문

Log.txt 파일이 존재하면 예외 내용을 기록합니다.

Log.txt 파일이 존재하지 않으면 원래 예외를 FileNotFoundException의 두 번째 인자로 전달합니다.

 

외부 catch문

InnerExceptoin 프로퍼티가 존재하면, InnerException의 내용을 콘솔에 출력합니다.

class Program
{
  static void Main(string[] args)
  {
    int a, b, c;

    try // 1. 외부 try문
    {
      try // 2. 중첩된 try문
      {
        a = int.Parse(Console.ReadLine());
        b = int.Parse(Console.ReadLine());
        c = a / b;
        Console.WriteLine("C VALUE = " + c);
      }
      catch (Exception e) // 3. 중첩된 catch문
      {
        Console.WriteLine("\n내부 catch문 실행");
        Console.WriteLine(e.Message + "\n");

        string filePath = @"C:\LogDirectory\Log.txt";
        if (File.Exists(filePath))
        {
          StreamWriter sw = new StreamWriter(filePath);
          sw.Write(e.Message);
          sw.Close();
        }
        else
        {
          throw new FileNotFoundException(filePath + " Does not Exist", e);
        }
      }
    } 
    catch(Exception e) // 4. 외부 catch문
    {
      Console.WriteLine("\n외부 catch문 실행");
      Console.WriteLine(e.Message + "\n");
      
      if(e.InnerException != null)
      {
        Console.WriteLine("\nInnerException");
        Console.WriteLine(e.InnerException.Message);
      } 
    }
  }
}

[실행 결과]

100
0

내부 catch 실행
Attempted to divide by zero.


외부 catch 실행
C:\LogDirectory\Log.txt Does not Exist


InnerException
Attempted to divide by zero.
  1. 100과 0을 입력합니다. 내부 catch문에서 DivdeByZeroException이 발생하였으며, Log.txt 파일이 존재하지 않으면 예외 생성자의 두 번째 인자에 현재 예외를 전달합니다.
  2. Log.txt 파일이 존재하지 않으므로 외부 catch문이 실행되었습니다. InnerException 프로퍼티에는 내부 catch문의 원인이었던 예외를 확인할 수 있습니다.

위 예체처럼 내부 catch문에서 예외 클래스 생성자 두 번째 인자로 현재 예외를 전달하면, 외부 catch문에서도 내부 catch문이 발생한 예외를 확인할 수 있습니다.

반응형

댓글