2020. 1. 26. 18:33ㆍC# 언어/이것이 C# 이다. 책정리
챕터 12 '예외 처리하기'입니다
프로그램이 비정상적인 상황을 만났을 때 이를 처리하는 예외 처리를 배웁니다.
'이것이 C#이다' 교재를 바탕으로 정리했습니다.
이전 정리 글
2020/01/06 - [이것이 C#이다./이것이 C# 이다. 책 정리] - Ch01 프로그래밍을 시작합시다.
2020/01/06 - [이것이 C# 이다./이것이 C# 이다. 책정리] - Ch02 처음 만드는 C# 프로그램
2020/01/06 - [이것이 C# 이다./이것이 C# 이다. 책정리] - Ch03 데이터 보관하기
2020/01/07 - [이것이 C#이다./이것이 C# 이다. 책 정리] - 부록A. 문자열 다루기
2020/01/07 - [이것이 C# 이다./이것이 C# 이다. 책정리] - Ch04. 데이터를 가공하는 연산자
2020/01/08 - [이것이 C# 이다./이것이 C# 이다. 책정리] - Ch05 코드의 흐름 제어하기
2020/01/09 - [이것이 C#이다./이것이 C# 이다. 책 정리] - ch06 메소드로 코드 간추리기
2020/01/11 - [이것이 C# 이다./이것이 C# 이다. 책정리] - ch07 클래스
2020/01/17 - [이것이 C# 이다./이것이 C# 이다. 책정리] - ch08 인터페이스와 추상 클래스
2020/01/18 - [이것이 C# 이다./이것이 C# 이다. 책정리] - ch09 프로퍼티
2020/01/19 - [이것이 C# 이다./이것이 C# 이다. 책정리] - ch10 배열과 컬렉션, 그리고 인덱서
ㅇ 예외에 대하여 |
프로그래머가 생각하는 시나리오에서 벗어나는 사건,
이것을 "예외"라고 부르는 한편,
예외가 프로그램의 오류나 다운으로 이어지지 않도록 적절하게 처리하는 것을
"예외 처리"라고 합니다.
예를 들어봅시다.
int[] arr = {1,2,3};
for (int i = 0; i < 5; i++)
{
Console.WriteLine(arr[i])
}
for문은 배열의 크기를 벗어난 출력을 요구하기 때문에 오류가 발생합니다.
이때 오류 내용은
IndexOutOfRangeException : 인덱스가 배열 범위를 벗어났습니다.
이 메시지는 CLR이 출력한 것입니다.
잘못된 인덱스를 통해 배열의 요소에 접근하려 들면 배열 객체가 이 문제에 대한 상제 정보를
IndexOutOfRangeException의 객체에 담은 후 Main() 메서드에게 던집니다.
위 예제에는 예외를 처리하는 방도가 없기 때문에 다시 CLR에게 던집니다.
CLR에게까지 전달된 예외는 "처리되지 않은 예외"로써 CLR은 이것을 받으면
예외 객체에 담긴 내용을 사용자에게 출력하고 프로그램을 종료시킵니다.
ㅇtry ~ catch로 예외 받기 |
try 절에서 원래 실행하고자 했던 코드를 쭉 처리해나가다가
예외가 던져지면 catch 블록이 받아냅니다.
catch 절은 try 블록에서 던질 예외 객체와 형식이 일치해야 됩니다.
위에 예제를 예외 처리해보겠습니다.
int[] arr = {1,2,3};
try // 예외 던짐
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine(arr[i])
}
}
catch ( IndexOutOfRangeException e) // 예외 받기
{
Console.WrteLine($"예외가 발생했습니다. : {e.Message}");
}
ㅇ 예외 던지기 |
예외를 우리가 직접 던지는 방법입니다.
throw 문을 이용해서 필요에 의한 예외를 던집니다.
예제를 통해 바로 보겠습니다.
using System;
using static System.Console;
namespace p407
{
class Program
{
static void DoSomething(int arg)
{
if (arg < 10)
{
WriteLine($"arg : {arg}");
}
else
throw new Exception("arg가 10보다 큽니다."); // throw를 통해
} // Exception 형식 예외를 던짐
static void Main(string[] args)
{
try
{
DoSomething(1);
DoSomething(3);
DoSomething(5);
DoSomething(9);
DoSomething(11); // 10보다 큰 수는 else구문의 throw절을 만나게됨.
DoSomething(13); // 실행되지 않음
}
catch(Exception e) // Exception 형식을 받아
{
WriteLine(e.Message); // Error내용을 출력함
}
}
}
}
throw는 보통 문으로 사용하지만 C# 7.0부터는 식으로도 사용할 수 있도록 개선되었습니다.
int? a = null;
int b = a ? throw new ArgumnetNullException();
'?'의 조건 연사자는 a가 null 인지 판단하고
null이면 throw 식이 실행
null이 아니면 a값이 대입됩니다.
ㅇ try ~ catch와 finally |
c#에서는 예외 처리를 할 때 자원 해제 같은 뒷마무리를 우아하게 할 수 있도록 finally 절을 지원합니다.
자신이 소속되어 있는 try 절이 실행된다면 fially 절은 어떤 경우에라도 실행됩니다.
심지어 return 문이나 throw문이 사용되더라도요.
예제를 보겠습니다.
using System;
using static System.Console;
namespace p412
{
class Program
{
static int Divide(int divisor, int dividend)
{
try
{
WriteLine("Divide() 시작");
return divisor / dividend;
}
catch (DivideByZeroException e)
{
WriteLine("Divide() 예외 발생");
throw e;
}
finally
{
WriteLine("Divide() 끝"); //어떠한 경우에도 실행됩니다.
}
}
static void Main(string[] args)
{
try
{
Write("제수를 입력하세요.");
string temp = ReadLine();
int divisor = Convert.ToInt32(temp);
Write("피제수를 입력하세요.");
temp = ReadLine();
int dividend = Convert.ToInt32(temp);
WriteLine("{0}/{1} = {2}",
divisor, dividend, Divide(divisor, dividend));
}
catch (FormatException e)
{
WriteLine("에러 : " + e.Message);
}
catch (DivideByZeroException e)
{
WriteLine("에러 : " + e.Message);
}
finally
{
WriteLine("프로그램을 종료합니다.");
}
}
}
}
ㅇ 예외 필터하기 |
C# 6.0부터는 catch 절이 받아들일 예외 객체에 제약 사항을 명시해서 해당 조건을 만족하는 예외 객체에 대해서만
예외 처리 코드를 실행할 수 있도록 하는 "예외 필터"가 도입됐습니다.
단순히 catch() 문 뒤에 when 키워드를 이용해서 제약 조건을 기술하면 됩니다.
using System;
using static System.Console;
namespace p418
{
class FilterableeException : Exception
{
public int ErrorNo { get; set; }
}
class Program
{
static void Main(string[] args)
{
WriteLine("Enter Number Between 0~10");
string input = ReadLine();
try
{
int num = Int32.Parse(input);
if(num < 0 || num > 10)
{
throw new FilterableeException() { ErrorNo = num };
}
else
{
WriteLine($"Output: {num}");
}
}
// when 키워드로 e.ErrorNo의 값이 < 0 음수일때 실행
catch (FilterableeException e ) when (e.ErrorNo < 0)
{
WriteLine("Negative input is not allowed.");
}
// when 키워드로 e.ErrorNo의 값이 > 10 양수일때 실행
catch(FilterableeException e) when (e.ErrorNo > 10)
{
WriteLine("Too big number is not allowed.");
}
}
}
}