.NET/C#

[C#] 예외처리

클리엘 2022. 6. 24. 11:41
728x90

1. 예외처리

 

위의 Parse()메서드를 설명할 때 이미 Runtime에러가 발생하는 경우를 봤었는데 이런 경우를 '예외가 발생했다.'라고도 표현합니다. 예외가 발생하면 try ~ catch를 사용하는 경우 에러를 제어할 수 있는 여지가 주어지지만 그렇지 않다면 stack trace를 포함한 예외 관련 메시지를 출력하고 Application의 동작은 중지됩니다.

try {
    string s = "abc";
    int i = int.Parse(s);
}
catch {
    
}

예제에서처럼 try ~ catch는 예외가 발생할 수 있는 코드 전체를 try { } 안에서 실행하도록 할 수 있으며 예외가 발생되는 경우만 catch { } 내부로 처리가 이루어지게 됩니다. 위에서 'Unhandled exception'가 발생하고 처리가 중단되는 것 과는 다르게 예외에 대한 메시지 없이 Application의 처리는 계속 진행될 수 있습니다.

 

catch안에서는 예외에 대한 Type을 적절히 파악하기 위해서 System.Exception을 catch안에서 사용할 수 있습니다.

try {
    string s = "abc";
    int i = int.Parse(s);
}
catch (System.Exception ex) {
    Console.WriteLine($"{ex.GetType()} - {ex.Message}");
}
//System.FormatException - Input string was not in a correct format.

혹은 예외가 발생할 수 있는 Type이 명확하다면 해당 Type을 직접 지정해 줄 수도 있습니다.

try {
    string s = "abc";
    int i = int.Parse(s);
}
catch (System.FormatException) {
    Console.WriteLine("문자열 형식이 잘못되었습니다.");
}
catch (System.Exception ex) {
	Console.WriteLine($"{ex.GetType()} - {ex.Message}");
}

System.Exception은 모든 예외 형식에서 상속받는 가장 상위의 예외 형식이며 System.FormatException이후에 System.Exception을 다시 남겨두는 이유는 System.FormatException 이외에 다른 예외가 발생하는 경우를 대비하기 위한 것입니다.

 

● filter 적용

 

try ~  catch에서 catch는 다음과 같이 when키워드를 사용해 filter를 적용할 수 있습니다.

string s = "abc";
try {
    int i = int.Parse(s);
}
catch (System.FormatException) when (s.Trim() == "abc") {
    Console.WriteLine("abc는 정수로 변환될 수 없습니다.");
}
catch (System.Exception ex) {
	Console.WriteLine($"{ex.GetType()} - {ex.Message}");
}
//abc는 정수로 변환될 수 없습니다.

2. 오버플로우(overflow)

 

어떤 값이 특정 변수가 담을 수 있는 값의 범위를 넘어서게 되면 이것을 우리는 오버플로우(overflow)라고 표현합니다. 오버플로우가 발생하면 별다른 예외는 발생하지 않고 해당 변수는 자신의 Type에서 가질 수 있는 최솟값으로 초기화됩니다.

int i = int.MaxValue; //int의 최대값으로 설정
Console.WriteLine(i); //2147483647
++i; //오버플로우
Console.WriteLine(i); //-2147483648

예외를 발생시키지 않는 건 성능 문제인데 이를 방지하고 오버플로 우발 생시 예외를 일으키려면 필요한 구문 전체를 checked로 감싸줄 수 있습니다.

checked {
    int i = int.MaxValue; //int의 최대값으로 설정
    Console.WriteLine(i); //2147483647
    ++i; //오버플로우
    Console.WriteLine(i);
}
//Unhandled exception. System.OverflowException: Arithmetic operation resulted in an overflow.
//  at Program.<Main>$(String[] args) in C:\Users\Administrator\Downloads\csharp\Program.cs:line 12

checked를 try ~ catch와 혼동해서는 안됩니다. overflow예외는 기본적으로는 예외 자체가 발생하지 않으므로 try ~ catch로도 잡아낼 수 없습니다. catch로 잡아내려면 checked를 감싸고 난 후 해당 구문 자체를 try ~ catch안에 배치해야 합니다.

try {
    checked {
        int i = int.MaxValue; //int의 최대값으로 설정
        Console.WriteLine(i); //2147483647
        ++i; //오버플로우
        Console.WriteLine(i);
    }
}
catch (OverflowException)
{
    Console.WriteLine("오버플로우 발생");
}
//오버플로우 발생

위에서 언급한 checked와 예제는 runtime에서의 overflow동작 와 이를 제어하기 위한 것입니다. 그러나 구문 자체만 명확하다면 overflow는 runtime이 아닌 compile에서 overflow예외를 감지할 수 있습니다.

이런 경우 예외를 발생시키지 않게 하려면 unchecked를 사용할 수 있습니다. unchecked는 compile time에서 overflow예외를 발생시키지 않도록 합니다.

unchecked {
    int i = int.MaxValue + 1;
}

 

728x90