ch12 예외 처리하기

2020. 1. 26. 18:33C# 언어/이것이 C# 이다. 책정리

반응형

 

챕터 12  '예외 처리하기'입니다

프로그램이 비정상적인 상황을 만났을 때 이를 처리하는 예외 처리를 배웁니다.

 

'이것이 C#이다' 교재를 바탕으로 정리했습니다.

 

이전 정리 글

더보기

ㅇ 예외에 대하여

 

프로그래머가 생각하는 시나리오에서 벗어나는 사건, 

이것을 "예외"라고 부르는 한편,

예외가 프로그램의 오류나 다운으로 이어지지 않도록 적절하게 처리하는 것을 

"예외 처리"라고 합니다.

 

예를 들어봅시다.

int[] arr = {1,2,3};

for (int i = 0; i < 5; i++)
{
	Console.WriteLine(arr[i])
}   

for문은 배열의 크기를 벗어난 출력을 요구하기 때문에 오류가 발생합니다.

이때 오류 내용은

 

IndexOutOfRangeException : 인덱스가 배열 범위를 벗어났습니다.

 

이 메시지는 CLR이 출력한 것입니다.

잘못된 인덱스를 통해 배열의 요소에 접근하려 들면 배열 객체가 이 문제에 대한 상제 정보를

IndexOutOfRangeException의 객체에 담은 후 Main() 메서드에게 던집니다.

위 예제에는 예외를 처리하는 방도가 없기 때문에 다시 CLR에게 던집니다.

CLR에게까지 전달된 예외는 "처리되지 않은 예외"로써 CLR은 이것을 받으면

예외 객체에 담긴 내용을 사용자에게 출력하고 프로그램을 종료시킵니다.

 

Main에서 예외 처리를 하지 않을 경우에 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.");
            }
        }
    }
}

 

 

반응형