NGMsoftware

NGMsoftware
로그인 회원가입
  • 매뉴얼
  • 학습
  • 매뉴얼

    학습


    C# 32-3. C#의 사용자 예외 처리와 복구. (Custom exception, Finally)

    페이지 정보

    본문

    안녕하세요. 소심비형입니다. 예외처리의 마지막으로 finally에 대해 알아보겠습니다. 대부분 솔루션이나 패키지가 아닌 SI에서 개발하고 있을겁니다. 우리나라만큼 패키지가 성공하기 힘든 나라도 없죠-_-; 중소기업이 기술을 보유하게되면 시장에서 성공하는게 아니라 대기업의 먹잇감이 되는게 현실입니다. 지금은 많이 좋아지긴 했지만, 아직도 기술력만으로 중소기업이 자생하기에는 무리가 따르죠^^; 그래서 보통 대기업과 관계를 맺고 커스터마이징하면서 제품화합니다. 하지만, 이것도 극히 일부의 이야기입니다-_-;

     

    이 이야기를 꺼낸 이유는 대부분의 개발자가 Custom Exception을 만들일이 없기 때문입니다. SI의 경우에는 회사에서 제공하는 프레임워크를 사용해서 화면을 찍어내게 되는데 이 때 특별한 기술이 필요한건 아니기 때문입니다. 개발 스킬보다는 업무(반도체, 금융, 빌링, 학사관리등등...)를 더 잘 알아야 하는 경우가 많습니다.

    plZB4O9.jpg

     

     

    사실 Framework를 도입하는 이유가 균일한 품질의 코드를 생산하기 위함이죠. 그렇기에 일반적이지 않은 코드가 많을수록 유지보수에 어려움이 생기게 됩니다. 개발자가 모두 같은 실력을 가진건 아니니까요. 그래서 가급적이면 쉽고 간결한 코드만을 이용해서 화면을 찍어내는게 좋습니다. 무리한 기능을 넣기 위해 기교를 부리기 보다는 고객과 협의해서 기능을 빼는게 더 좋다는 뜻입니다.

     

    오늘 알아볼 finally는 거의 사용되지 않습니다. MVC나 MVP 또는 3Layer, 3Tier와 같은 구조를 가지게 되면 finally는 더더욱 볼일이 없게되죠? 대부분 Exception을 던지니까요. 하지만 Frontend의 경우에는 약간 다릅니다. 최종 처리 단계에서까지 Exception을 던져버리면 사용자에게 System Error Message를 보여주게 됩니다. 이는 사용자 친화적이지 않으며, 문제를 해결하는데 더 어렵죠. End-user는 개발자가 아니니까요.

    이런 메시지는 개발자만 보는게 좋습니다-_-;

    UmY6BFL.jpg

     

     

    시나리오는 이렇습니다. try에서 복잡한 로직을 처리하고 catch에서 예외를 개발자가 알기 쉽도록 로깅합니다. 물론, File이나 Database를 이용하게 되겠죠? 그리고 마지막으로 오작동을 방지하기 위해 에러가 발생한 개체들을 다시 복구할 필요가 있습니다. 이 때 finally 블록에서 개체들을 초기화하거나 복구합니다.

     

    아래 예제는 클래스를 복구하거나 하는 복잡한 내용은 아니지만, finally를 이해하는데 도움이 될거에요.

    Program.cs

    using System;
    namespace Finally
    {
        class Program
        {
            static int Divide(int divisor, int dividend)
            {
                try
                { Console.WriteLine("Divide() 시작"); return divisor / dividend; }
                catch (DivideByZeroException e) { Console.WriteLine("Divide() 예외 발생"); throw e; }
                finally
                {
                    Console.WriteLine("Divide()  끝");
                }
            }
            static void Main(string[] args)
            {
                try
                {
                    Console.Write("제수를 입력하세요. :");
                    String temp = Console.ReadLine();
                    int divisor = Convert.ToInt32(temp);
                    Console.Write("피제수를 입력하세요. : ");
                    temp = Console.ReadLine();
                    int dividend = Convert.ToInt32(temp);
                    Console.WriteLine("{0}/{1} = {2}", divisor, dividend, Divide(divisor, dividend));
                }
                catch (FormatException e) { Console.WriteLine("에러 : " + e.Message); }
                catch (DivideByZeroException e) { Console.WriteLine("에러 : " + e.Message); }
                finally
                {
                    Console.WriteLine("프로그램을 종료합니다.");
                }
            }
        }
    }
    

     

     

    finally는 catch에서 예외를 throw하더라도 먼저 실행되고 제어를 넘기게 됩니다. finally 블록은 건너뛸 수 없으며 반드시 실행됩니다. 그렇기 때문에 프로그램에 심각한 문제를 일으킬만한 작업이라면 finally에 문제를 제거할 수 있도록 코드를 추가하세요. 대부분 큰 실수를 하는 부분은 아래와 같습니다. File stream을 열어둔 후 어떤 문제가 발생해서 catch로 이동한 경우입니다. 이 때 catch에서 File Stream을 닫아주면 좋겠지만 대부분 그렇지 못합니다. 그래서 문제를 일으키게 되죠. 더 심각한건 Database입니다. 세션을 열어두고 닫지 않거나 Lock을 해제하지 않는 경우들입니다. 이외에도 메모리 문제나 네트워크 소켓등등 많습니다.

    아래 예제는 Custom exception을 만드는 방법을 보여줍니다.

    Program.cs

    using System;
    
    namespace MyException
    {
        class InvalidArgumentException : Exception
        {
            public InvalidArgumentException() { }
            public InvalidArgumentException(string message) : base(message) { }
            public object Argument { get; set; }
            public string Range { get; set; }
        }
        class Program
        {
            static uint MergeARGB(uint alpha, uint red, uint green, uint blue)
            {
                uint[] args = new uint[] { alpha, red, green, blue };
                foreach (uint arg in args)
                { if (arg > 255) throw new InvalidArgumentException() { Argument = arg, Range = "0~255" }; }
                return (alpha << 24 & 0xFF000000) | (red << 16 & 0x00FF0000) | (green << 8 & 0x0000FF00) | (blue & 0x000000FF);
            }
            static void Main(string[] args)
            {
                try
                {
                    Console.WriteLine("0x{0:X}", MergeARGB(255, 111, 111, 111));
                    Console.WriteLine("0x{0:X}", MergeARGB(1, 65, 192, 128));
                    Console.WriteLine("0x{0:X}", MergeARGB(0, 255, 255, 300));
                }
                catch (InvalidArgumentException e)
                {
                    Console.WriteLine(e.Message);
                    Console.WriteLine("Argument:{0}, Range:{1}", e.Argument, e.Range);
                }
            }
        }
    }

     

     

    Custom exception을 만들려면 무조건 Exception을 상속 받아서 구현해야 합니다. 이것만 지켜주면 되죠. 하지만, 여기서 좀 더 추가한다면 정보를 제공하는 Argument 개체도 별도로 만들어서 초기화하는게 좋습니다. 에러가 발생한 상황을 해결하기 위한 방법을 풍부하게 제공하기 위해서죠.

    yD9Oz07.jpg

      

     

    이렇게 해서 예외(Exception)에 대해 알아보았습니다. 깊이 있게 알아보려면 더 많은 시간을 할애해야 하지만, 말로 표현하는 것보다 제약이 많아서 어렵군요-_-; 가능하면 MSDN과 책을 통해 세부적인 내용에 대해 알아가는게 좋겠습니다.

     

    다음 시간에...

    • 네이버 공유하기
    • 페이스북 공유하기
    • 트위터 공유하기
    • 카카오스토리 공유하기
    추천0 비추천0

    댓글목록

    등록된 댓글이 없습니다.