Programming with C#/C# 기초문법

[C# 기초문법] 7. 예외처리 (Exception Handling)

laboputer 2015. 1. 25. 23:09



 

예외(Exception)

 프로그래밍을 하다보면 수많은 예외상황들을 접하게 됩니다.

C#은 여러가지 예외클래스를 제공합니다.(DivideByZeroException, IndexOutOfRangeException, NullReferenceException 등)

여러가지 예외(Exception)가 발생했을 때 이 예외로 인해 프로그램이 종료되지 않고 다시 제대로 흘러가도록 예외마다 적절한 대처를 해주어야 합니다.

먼저, 한가지 예외를 발생시키고 설명하겠습니다.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CsharpStudy
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] Numbers = new int[5] { 1, 2, 3, 4, 5 };

            for(int i=0; i<6; i++)
            {
                    Console.WriteLine(Numbers[i].ToString());
            }
        }
    }
}

 

위와 같이 잘못된 인덱스를 통해 접근하려하면 문제의 상세정보를 IndexOutOfRangeException의 객체에 담은 후 Main() 메소드로 던집니다. 여기서 예외처리를 하지 않았기 때문에 Main() 메소드는 다시 CLR에게 던집니다.

CLR이 '인덱스가 배열 범위를 벗어났습니다.'는 문구를 띄우면서 프로그램이 강제종료 되는 모습을 보실 수 있습니다.

위의 메시지는 CLR이 예외처리를 하라고 프로그래머한테 메시지를 보낸 것입니다. (이것도 일종의 예외처리겠지요.)

즉, 프로그래머가 예외처리를 하지 않았기 때문에 프로그램은 강제종료가 됩니다.

 

 

예외처리(Exception Handling)

 예외처리는 if~else로도 전부 처리할 수 있습니다. 하지만, 예외에 대한 대처인지, 실제 문제처리하는 코드인지, 가독성도 좋지 않을 뿐더러 예외가 여러가지일때 무슨 예외상황인지도 파악하기가 어렵습니다. 또, 같은 예외가 여러군데에서 발생하면 일일이 다 처리해야합니다. 하지만 C#에서 예외처리문을 사용할 경우에는 위의 문제가 전혀 발생하지 않습니다. 

 

C#에서 예외처리는 try~catch 문을 이용합니다.

try

{

//실행코드

}

catch (예외 객체1)

{

//예외1에 대한 처리

}

catch (예외 객체2)

{

//예외2에 대한 처리

}

 

finally

{

// 반드시 실행되는 코드

}

 

 

위에서 발생했던 예외에 대한 처리를 해보겠습니다.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CsharpStudy
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] Numbers = new int[5] { 1, 2, 3, 4, 5 };

            for(int i=0; i<6; i++)
            {
                try
                {
                    Console.WriteLine(Numbers[i].ToString());
                }
                catch (IndexOutOfRangeException e)
                {
                    Console.WriteLine("예외메시지 : {0}", e.Message);
                    Console.WriteLine("예외가 발생한 곳(namespace): {0}", e.Source);
                    Console.WriteLine("예외가 발생한 곳(method): {0}", e.TargetSite);
                    Console.WriteLine("예외가 발생한 곳(line): {0}", e.StackTrace);               
                }
            }

            Console.WriteLine("예외 상황이 끝난 후..");
        }
    }
}

 

예외클래스에는 예외에 대한 여러가지 정보가 담겨있습니다.

또한 예외처리를 할 경우 프로그램이 종료되지 않고 다음 코드가 정상적으로 작동되는 것을 확인하실 수 있습니다.

 

try블록에서 자원해제와 같은 중요한 코드를 미처 실행하지 못한 상태로 예외를 발생시키게 된다면, 이는 곧 버그를 만드는 원인이 됩니다. 예를 들어 DB Connection을 닫는 코드를 실행하지 못할 경우에는 사용할 수 있는 커넥션이 점점 줄어 DB에 연결할수 없는 상태에 도달할 수 있습니다. 따라서 finally 절을 지원합니다. finally 절은 try절이 실행된다면 어떤 경우에라도 실행됩니다. 심지어 return 문이나 throw 문이 사용되도 finally 절은 반드시 실행됩니다.

 

 

System.Exception Class

 C#에서 모든 예외 클래스는 반드시 이 클래스로부터 상속받아야 합니다.

즉, 상속 관계로 인해 모든 예외클래스는 System.Exception 형식으로 간주하여 catch절 하나면 모든 예외를 다 받을 수도 있습니다. 하지만 예외마다 다른 대처를 해야한다면, 프로그래머는 예외상황에 따라 맞는 코드를 작성해야 합니다.

예외처리는 깊게 생각하여 정확히 처리해야합니다. 대충 try~catch문을 사용했다가는 프로그램이 흘러가면서 버그가 발생하는데도 프로그램이 종료되지 않아 버그를 찾기가 매우 어려워집니다.

 

 

사용자 정의 예외 클래스 만들기

 C#에서는 모든 예외 객체는 System.Exception 클래스로부터 파생되어야 합니다. 이를 상속하기만 하면 프로그래머가 직접 새로운 예외 클래스를 만들수 있습니다. C#에서는 100가지 넘는 예외 클래스를 제공하지만, 사용자가 직접 예외를 발생하고 싶은 경우도 있습니다.

예를 들면 회원가입 할때 비밀번호는 8자리 이상을 입력해야 된다거나, 영문을 섞어야 할때 프로그래머는 이를 지키지 않을 경우 예외를 발생시킬 수도 있습니다.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CsharpStudy
{
    class ShortPasswordException : Exception
    {
        public ShortPasswordException(string message) : base(message)
        {

        }

        public string Range
        {
            get;
            set;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            do
            {
                Console.WriteLine("비밀번호를 입력하세요!");
                string Password = Console.ReadLine();
                try
                {
                    if (Password.Length < 8)
                    {
                        throw new ShortPasswordException("비밀번호가 너무 짧습니다")
                        {
                            Range = "8자리 이상"
                        };
                    }
                    else
                    {
                        break;
                    }
                }
                catch (ShortPasswordException e)
                {
                    Console.WriteLine("예외메시지: {0}", e.Message);
                    Console.WriteLine("예외발생한곳: {0}", e.StackTrace);
                    Console.WriteLine("가능범위: {0}", e.Range);
                }              
            } while (true);
        }
    }
}
 

 

 

 

이상으로 예외처리에 대해서 정리해보았습니다.

 

 


<참고문헌>

뇌를 자극하는 C# 4.0 프로그래밍 - 박상현 저