외로운 Nova의 작업실

c# 언어 공부 - 8(예외 처리) 본문

Programming/C#

c# 언어 공부 - 8(예외 처리)

Nova_ 2022. 5. 7. 00:23

안녕하세요. 오늘은 저번시간에 이어서 c# 예외처리에대해서 배워보도록 하겠습니다.

 

<예외처리>

예외의 예시를 하나 들어보도록 하겠습니다.

먼저 코드부터 보시죠.

using System;

namespace StudyCSharp
{
    class MainApp
    {

        static void Main(string[] args)
        {
            int[] array = new int[3];

            array[3] = 4;

            Console.WriteLine("종료");

        }
       
        
    }
}

위와 같은 코드를 실행하게되면, 컴퓨터는 에러를 일으킵니다.

왜냐면 array배열의 크기는3인데, 즉 index가 2까지 밖에없는데 3에 접근하고있기 때문입니다.

또한 프로그램은 에러를 일으키고 다운되어버려 그 다음줄인 콘솔에 종료 출력을 안하게됩니다.

이렇게 프로그램이 에러를 일으키고 그냥 다운되어버리는 것들에대해서 조취를 취해야할 필요성이 있습니다.

 

<try~catch문>

먼저 예외를 처리하는 방법에는 try~catch문을 처리하는 방법이 있습니다.

코드 부터 보시죠.

using System;

namespace StudyCSharp
{
    class MainApp
    {

        static void Main(string[] args)
        {
            int[] array = new int[3];

            try //{}괄호안에 있는 코드를 실행하다가 예외를 만나면
            {
                array[3] = 4;

                Console.WriteLine("종료");
            }
            catch (IndexOutOfRangeException)//()괄호 안의 예외 객체가 반환되면 실행함
            {
                Console.WriteLine("배열에 유효하지않은 인덱스에 접근하고있습니다.");
            }

        }
       
        
    }
}

위 코드는 맨 처음에 프로그램이 다운되어버렷던 코드를 예외처리한 코드입니다.

그중 catch문 다음에는 예외객체를 적어줘야하는데요, 예외객체는 각 객체마다 예외를 일으키면 Main메소드에게 예외객체들을 던지게됩니다.

위 코드에서는 배열 객체가 index의 유효범위를 벗어나서 IndexOutOfRangeException이라는 예외 객체를 Main메소드에게 던지게되고, catch문은 던져진 객체중에 맞는 catch문을 골라 {}괄호안의 코드를 실행하게됩니다.

 

<System.Exceptiom 클래스>

모든 예외 클래스들은 System.Exception 클래스를 상속 받게됩니다.

즉 catch문에 Exception 객체를 넣게되면 모든 예외를 받아낼 수 있게된다는 것입니다.

코드를 보시죠.

using System;

namespace StudyCSharp
{
    class MainApp
    {

        static void Main(string[] args)
        {
            int[] array = new int[3];

            try
            {
                array[3] = 4;

                Console.WriteLine("종료");
            }
            catch (IndexOutOfRangeException)//유효하지않은 인덱스 사용시 던져지는 예외객체
            {
                Console.WriteLine("배열에 유효하지않은 인덱스에 접근하고있습니다.");
            }
            catch (DivideByZeroException)//0으로 나눌때 던져지는 예외 객체
            {
                Console.WriteLine("0으로 나눌 수 없습니다.");
            }

        }
       
        
    }
}

위 2가지 예외 객체를 아래 코드와 같이 Exception 객체로 다 받을 수 있습니다.

using System;

namespace StudyCSharp
{
    class MainApp
    {

        static void Main(string[] args)
        {
            int[] array = new int[3];

            try
            {
                array[3] = 4;

                Console.WriteLine("종료");
            }
            catch (Exception e)//모든 예외객체
            {
                Console.WriteLine("배열에 유효하지않은 인덱스에 접근하고있습니다.");
                Console.WriteLine("0으로 나눌 수 없습니다.");
            }
            

        }
       
        
    }
}

 

<예외던지기>

예외를 던지는것은 내부적으로 진행이되지만, 프로그래머가 직접 던질 수 도 있습니다.

이는 throw명령어를 사용해서 구현하게됩니다.

코드를 봅시다.

using System;

namespace StudyCSharp
{
    class MainApp
    {

        static void Main(string[] args)
        {
            int[] array = new int[3];

            try
            {
                int val = 3;

                if(val < 3)
                {
                    Console.WriteLine("유효한 val값입니다.");
                }
                else
                {
                    throw new Exception("유효하지않은 val값 입니다.");//예외객체의 Message필드에 ()괄호 안의 값을 넣어 던짐
                }
            }
            catch (Exception e)//모든 예외객체
            {
                Console.WriteLine(e.Message);
            }
            

        }
       
        
    }
}

위 코드의 실행결과는 아래와 같습니다.

 

<finally문>

try,catch문의 단점이 하나있습니다.

바로 try문에서 예외를 만나게되면 그 다음줄로 진행하지않고 예외를 처리하고 끝낸다는 것입니다.

코드를 보시죠.

using System;

namespace StudyCSharp
{
    class MainApp
    {

        static void Main(string[] args)
        {
            int[] array = new int[3];

            try
            {
                int val = 3;

                if(val < 3)
                {
                    Console.WriteLine("유효한 val값입니다.");
                }
                else
                {
                    throw new Exception("유효하지않은 val값 입니다.");

                    Console.WriteLine("프로그램을 종료합니다.");//위에서 예외코드를 던졋으므로 해당코드는 실행안함
                }
            }
            catch (Exception e)//모든 예외객체
            {
                Console.WriteLine(e.Message);
            }
            

        }
       
        
    }
}

저는 예외를 만나면 "프로그램을 종료합니다"를 콘솔에 출력해야겟다고 마음먹고 코드를 작성했습니다.

하지만 실제로 프로그램을 실행시켜보면 아래와같이 해당 문자열이 출력되지않습니다.

finally문

이를 해결하기위해 finally문이 사용됩니다.

예외를 만나도 꼭 처리해야하는 구문이있다면 finally문에 써두면 처리가 됩니다.

코드를 봅시다.

using System;

namespace StudyCSharp
{
    class MainApp
    {

        static void Main(string[] args)
        {
            int[] array = new int[3];

            try
            {
                int val = 3;

                if(val < 3)
                {
                    Console.WriteLine("유효한 val값입니다.");
                }
                else
                {
                    throw new Exception("유효하지않은 val값 입니다.");

                }
            }
            catch (Exception e)//모든 예외객체
            {
                Console.WriteLine(e.Message);
            }
            finally
            {
                Console.WriteLine("프로그램을 종료합니다."); //예외를 만나든 안만나든 무조건실행
            }
            

        }
       
        
    }
}

아래는 실행 결과입니다.

 

<사용자 정의 예외클래스>

c#에는 많은 예외 객체들을 제공하고있지만, 우리가 예외 객체를 만들고 사용할 수 있습니다.

예외객체들의 조상인 Excetion객체를 상속하면 예외 객체로 사용할 수 있습니다.

예를 들어, 쇼핑몰 웹사이트의 회원가입 페이지를 c#으로 구현하엿는데, 회원의 이메일 주소가 잘못 기제되었을경우 InvalidEmailAddress 예외 객체를 직접 생성하고 던지게 만들 수 있습니다.

코드를 보시죠.

using System;

namespace StudyCSharp
{
    class MainApp
    {

        static void Main(string[] args)
        {
            int[] array = new int[3];

            try
            {
                string Email = "1111";

                if(Email != "1111")
                {
                    Console.WriteLine("유효한 Email값입니다.");
                }
                else
                {
                    throw new InvalidEmailAddress("유효하지않은 Email값 입니다.");

                }
            }
            catch (Exception e)//모든 예외객체
            {
                Console.WriteLine(e.Message);
            }
            finally
            {
                Console.WriteLine("프로그램을 종료합니다."); //예외를 만나든 안만나든 무조건실행
            }
            

        }

        class InvalidEmailAddress : Exception
        {
            public InvalidEmailAddress() //생성자
            {

            }

            public InvalidEmailAddress(string message) : base(message) //message가 인수로 잇는 메소드
            {

            }

        }
       
        
    }
}

위 코드처럼 직접 만들고 쓸 수 있습니다.

 

<예외 필터하기>

예외에 필터를 적용하게되면 예외객체가 반환되더라도 catch문이 작동하지않게 만들 수 있습니다.

코드부터보시죠.

using System;

namespace StudyCSharp
{
    class MainApp
    {

        static void Main(string[] args)
        {
            int[] array = new int[3];

            try
            {
                string Email = "2222"; //7

                if(Email != "1111"  && Email != "2222")
                {
                    Console.WriteLine("유효한 Email값입니다.");
                }
                else
                {
                    throw new InvalidEmailAddress("2222");

                }
            }
            catch (InvalidEmailAddress e) when (e.Email != "2222") //예외 필터 적용
            {
                Console.WriteLine($"{e.Message}는 유효하지않은 메시지입니다.");
            }
            finally
            {
                Console.WriteLine("프로그램을 종료합니다."); //예외를 만나든 안만나든 무조건실행
            }
            

        }

        class InvalidEmailAddress : Exception
        {
            public string Email = "";
            public InvalidEmailAddress() //생성자
            {

            }

            public InvalidEmailAddress(string message) : base(message) //message가 인수로 잇는 메소드
            {
                Email = message;
            }

        }
       
        
    }
}

위 코드는 예외가 처리되지않습니다.

왜냐면 catch문에서 when (e.Email != "2222") 구문은 e.Email이 2222가 아닐경우에만 실행되도록 필터를 걸었기 때문입니다.

 

 

Comments