'try catch'에 해당되는 글 3건

Programming/.NET

C# 에서 예외를 처리하는 가장 기본적인 방법은 try ~ catch 구문을 사용하는 것입니다.

 

string s = null;
string a = s.ToString();

 

위 코드는 고의적으로 예외를 발생시키기 위해 작성된 것으로 위와 같이 try catch를 사용하지 않으면 프로그램은 예외를 발생시키고 강제로 종료될 것입니다.

 

try {
    string s = null;
    string a = s.ToString();
} catch (Exception e) {
    Console.WriteLine(e.Message);
}

 

물론 아래와 같이 명시적으로 예외를 발생시키는 것도 가능합니다.

 

try
{
    ApplicationException e = new ApplicationException("오류발생");
    throw e;
}
catch (Exception e)
{
    Console.WriteLine(e.Message);
}

 

try ~ catch는 해당 구문안에서 예외가 발생하는 경우 처리를 catch하위로 넘기게 됩니다. 이때 예외처리를 담당하게 되는 catch에서는 인자로 Exception 형식의 객체를 받아 이 객체를 통해  Console로 오류메세지를 출력하도록 하고 있습니다.

 

실제 프로그램에서는 초기화 되지 않은 개체의 접근에 대한 System.NullReference(위 예제에서 발생시키는 예외타입에 해당합니다.)나 배열의 잘못된 인덱스지정으로인한 System.IndexOutOfRangeException 등 발생하는 예외의 형식이 다양한데 필요할때 마다 예외형식에 맞는 인스턴스를 활용할 수 있습니다.

 

예제에서 사용된 System.Exception 형식은 가장 최상위의 예외타입에 해당하는 것으로 다른 예외형식들은 모두 System.Exception 으로부터 파생된것이며 예외형식을 직접 구현하는 경우도 System.Exception으로 부터 상속받는 방법으로 예외클래스를 구현해야 합니다. System.Exception를 상속받으면 기본적으로 예외에 대한 설명을 제공하는 Message나 예외를 발생시킨 메서드를 알 수 있도록 하는 StackTrace와 같은 속성을 사용할 수 있습니다.

 

단, StackTrace 속성을 사용하는 경우 정확하게 예외가 발생한 메서드를 파악하려면 해당 프로그램을 Debug로 빌드해야 합니다. Release로 하는 경우 컴파일과정에서 소스코드의 구조가 일부 변경될 수 있기 때문에 StackTrace의 정보는 정확하지 않을 수 있습니다.

 

catch에서 Exception예외를 직접받게되면 try catch안에 발생된 모든 예외를 처리하게 됩니다. 따라서 만약 예외가 발생되는 형태마다 다른 처리를 하고자 한다면 원하는 형식에 맞는 예외타입을 직접 지정해야 합니다.

 

try
{
    string s = "abc";
    string a = s.ToString();

    int[] i = new int[5] { 0, 1, 2, 3, 4 };
    i[5] = 5;
}
catch (NullReferenceException e) //객체참조 오류의 경우 처리부분
{
    Console.WriteLine("참조" + e.Message);
}
catch (IndexOutOfRangeException e) //배열 인덱스 오류의 경우 처리부분
{
    Console.WriteLine("배열" + e.Message);
}
catch (Exception e) {
    Console.WriteLine("그외" + e.Message);
}

 

오류가 발생하든 발생하지 않든 무조건 실행되어야 하는 처리가 필요하다면 finally 를 사용해야 합니다.

 

try
{
    string s = "abc";
    string a = s.ToString();

    int[] i = new int[5] { 0, 1, 2, 3, 4 };
    i[5] = 5;
}
catch (NullReferenceException e) //객체참조 오류의 경우 처리부분
{
    Console.WriteLine("참조" + e.Message);
}
catch (IndexOutOfRangeException e) //배열 인덱스 오류의 경우 처리부분
{
    Console.WriteLine("배열" + e.Message);
}
catch (Exception e)
{
    Console.WriteLine("그외" + e.Message);
}
finally {
    Console.WriteLine("오류발생 유무와 관련없이 무조건 실행");
}

 

지금까지는 이미 정해진 예외(System.NullReferenceException, IndexOutOfRangeException등)를 사용했습니다. 그러나 필요하다면 자신만의 예외타입을 직접 만들 수도 있습니다.

 

class PhoneNumberException : Exception
{
    public PhoneNumberException(string msg) : base(msg) { }
}

 

별도의 예외클래스를 만들고자 하는 경우에는 Exception 으로 부터 클래스를 상속받도록 합니다.

 

try
{
    string s = "010-1234-";

    if (s.Length < 12) {
        PhoneNumberException e = new PhoneNumberException("전화번호 오류입니다.");
        throw e;
    }
}
catch (PhoneNumberException e)
{
    Console.WriteLine(e.Message);
}

 

예제로 만든 예외클래스는 메세지를 전달받아 base 즉, 부모가 되는 Exception에 해당 메세지를 전달하는 단순한 역활만 수행합니다.

 

C# 6.0부터는 이 예외에 조건을 추가할 수 있게 되었습니다.

 

int i = 0;
string input = string.Empty;

try
{
    input = Console.ReadLine();
    i = int.Parse(input);
}
catch (Exception e)
{
    Console.WriteLine($"예외발생!{e.Message}");
}

 

위의 경우 입력값이 변수 i의 타입에 맞지 않으면 예외를 발생시키도록 처리되어 있는데 만약 input이 'abc'일때만 예외를 타도록 하고 싶다면

 

int i = 0;
string input = string.Empty;

try
{
    input = Console.ReadLine();
    i = int.Parse(input);
}
catch (Exception e) when (input.Trim() == "abc")
{
    Console.WriteLine($"abc - 예외발생!{e.Message}");
}
catch (Exception e)
{
    Console.WriteLine($"예외발생!{e.Message}");
}

 

catch뒤에 when을 주고 원하는 조건을 명시하면 됩니다. 이렇게 하면 해당 조건에 부합하는 경우에만 아래 예외로 처리가 이전됩니다. 만약 조건이 복잡하다면 메서드로 분리하여 조건을 지정할 수도 있습니다.

 

static bool check_input(string content)
{
    return (content.Trim() == "abc" ? true : false);
}

 

int i = 0;
string input = string.Empty;

try
{
    input = Console.ReadLine();
    i = int.Parse(input);
}
catch (Exception e) when (check_input(input))
{
    Console.WriteLine($"abc - 예외발생!{e.Message}");
}
catch (Exception e)
{
    Console.WriteLine($"예외발생!{e.Message}");
}

 

또한 catch 나 finally 안에서 await를 활용한 비동기 호출이 가능해졌습니다.

 

try
{
    input = Console.ReadLine();
    i = int.Parse(input);
}
catch (Exception e) when (check_input(input))
{
    Console.WriteLine($"abc - 예외발생!{e.Message}");
}
catch (Exception e)
{
    await Log(e);
}

 

static Task Log(Exception e)
{
    return Task.Factory.StartNew(() => {
        Console.WriteLine(e.Message);
    });
}

'Programming > .NET' 카테고리의 다른 글

[C#] 예외처리(try ~ catch)  (0) 2019.02.19
[C#] ? / Nullable  (0) 2019.02.12
[C#] partial  (0) 2019.02.07
[C#] 비동기 호출(asynchronous call)  (0) 2019.01.23
Debug / Release  (0) 2019.01.15
[ASP.NET MVC] Razor  (0) 2019.01.08
0 0
Programming/C C++
가장 흔히 사용되는 예외처리 대표 구문으로 try ~ catch 문이 있습니다.
try
{
   int x = 0;
   int y = 0;

   if (x == 0)
    throw 10;

   int i = x/y;
}
catch(int e)
{
   cout << "오류코드 " << e << "번 발생" << endl;
}
try 문 안에서 throw구문으로 특정 데이터형의 값을 전달하면 catch 문의 인자(int e)에서 이 값을 받아 예외를 처리하게 됩니다. 따라서 throw에서 던지는 값의 데이터형과 catch에서 받는 데이터형은 항상 일치해야 합니다.

만약 여러 데이터형의 오류값을 throw하는 경우라면 다음처럼 catch를 그만큼 중복해서 만들 수 있습니다.
catch(int e)
{
   cout << "오류코드 " << e << "번 발생" << endl;
}
catch(char e)
{
   //
}
그런데 try안에서 던지는 throw는 반드시 try안에 있을 필요는 없습니다. 대신 최초 throw가 시작되면 항상 그 끝에는 catch가 throw값을 받을 수 있는 구조로 되어 있어야 합니다.
int plus(int i, int j)
{
   throw 0;
   return i + j;
}

int main()
{
   try
   {
      int x = plus(100, 200);
   }
   catch(int e)
   {
      cout << "오류코드 " << e << "번 발생" << endl;
   }

    return 0;
}

try 안에서 plus를 호출하고 plus안에서 throw 발생시킵니다. throw가 처음 plus에서 예외를 받아줄 catch를 찾고 그 안에서 catch가 존재하지 않으면 plus를 빠져나와 다시 catch를 찾게 됩니다. plsu함수를 빠져나오면 try안이고 이 안에 catch가 존재하게 되므로 결국 throw은 try안의 catch를 찾아가게 되는 것입니다.


예외처리를 좀더 구조화 하려면 예외처리 자체를 클래스로 만들어 사용합니다.
class exc
{
public:
   exc(int number, const char* msg) : e_number(number)
   {
      strcpy_s(e_msg, msg);
   }

   int get_e_number();
   const char* get_e_msg();

private:
   int e_number;
   char e_msg[255];
};

int exc::get_e_number()
{
   return e_number;
}

const char* exc::get_e_msg()
{
   return e_msg;
}
exc 라는 클래스는 오류코드와 그 내용을 받는 예외전용 클래스로서 클래스를 생성할때 생성자로부터 오류 번호와 오류 내용을 받으며 이를 다시 가져올 수 있는 멤버함수를 포함하고 있습니다.
try
{
   throw exc(100, "에러발생");
}
catch(exc& e)
{
   cout << "오류코드 " << e.get_e_number() << "번 " << e.get_e_msg() << endl;
}
예외 발생시 exc 클래스에 처리하고자 하는 오류번호와 내용을 전달합니다. catch에서 어떠한 자료형이든 받을 수 있다는 점을 이용한 것인데 자세히 보시면 &를 붙여 참조를 통해 try에서 생성한 객체에 접근하고 있음을 알 수 있습니다.

try안에서 생성한 객체는 try를 벗어나면(catch에 도달하면) 객체가 소멸되므로 C++에서는 객체를 throw하는 경우 객체의 복사본을 생성하게 됩니다. 따라서 catch에서는 이 복사본의 참조를 받아오도록 하는 것이죠. 물론 &를 제거하고 값자체로서 받아올 수 있으나 이렇게 되면 복사본을 다시 복사해버리는 성능상의 손실을 발생시킬 수 있으므로 권장하지 않습니다.
0 0
Programming/Microsoft SQL Server
Query에서는 문법적인오류를 제외한 대부분의 오류는 Try / Catch문으로 처리가 가능합니다.

Begin Try
     Select 10/0;
End Try
Begin Catch
      Select 'Error';
End Catch

Begin Try와 End Try사이에 있는 Query문 수행시 오류가 발생할 경우 Begin Catch와 End Catch사이에 있는 Query문을 대신 실행하도록 합니다.


Try Catch문을 통해 오류를 처리하는 경우 정확히 어떠한 내용의 오류가 발생하는지 확인해 보려면 <2-1>에 표시하고 있는 함수를 사용합니다. 오류 정보를 확인할 수 있는 함수는 대개 Error로 시작하는 함수이며 그 종류와 내용은 다음과 같습니다.

 error_line()  오류가 발생한 행수를 나타냅니다.
 error_message()  어떠한 오류인지 그 내용을 표시합니다.
 error_number()  오류번호를 나타냅니다.
 error_procedure()  오류가 발생한 해당 Procedure, Triger등의 이름을 나타냅니다.
 error_severity()  오류 심각도를 나타냅니다.
 error_state()  오류 상태를 나타냅니다.

숫자형태로 표시되는 심각도는 그 내용에 따라 의미가 각기 다릅니다. 자세한 내용은 아래 표를 참고하십시오.

 10 ~ 16  사용자의 잘못으로 인한 오류입니다.
 17 ~ 25  Software및 Hardware관련 오류입니다.(17 ~ 19 까지는 상황에 따라 오류가 발생하여도 작업은 계속 진행될 수 있습니다.)

Begin Try
     Select 10/0;
End Try
Begin Catch
      Select error_line(), error_message(), error_number(), error_procedure(), error_severity(), error_state()
End Catch

오류함수를 이용하여 error에 관한 자세한 정보를 표시하도록 하고 있습니다.


Try / Catch문을 Procedure안에 포함시키면 특정 오류가 발생했을때 자동 Rollback하도록 처리 할 수 있습니다.

Begin Try
 Begin Tran
  Insert Into HumanResources.Department
  Values('QC', 'QC Management', getdate());
 
  Insert Into HumanResources.Department
  Values('QA', 'QA Management', getdate());
 
  Select 10/0;
 
  Commit;
End Try
Begin Catch
 Rollback;
 Select 'Error';
End Catch
Select * From HumanResources.Department;

Insert문을 두번 실행한뒤 10을 0으로 나누는 오류를 일으키도록 하였습니다. 오류가 발생하면 Catch부분을 통해 Rollback되고 'Error'이라는 문구를 표시할 것입니다.


참고로 고의적으로 예외(오류)를 발생시킬 수도 있는데 이때는 Raiserror이나 Throw등이 사용됩니다. Raiserror에 대해서는 아래 링크를 참고해 주십시오.

2010/01/25 - [Programming/Microsoft SQL Server] - [SQL] Message 처리


Throw의 사용방식은 아래와 같습니다.


Throw 55555, N'오류 발생', 1;


Throw의 첫번째 인자는 오류번호를 의미합니다. 임의로 50000~21억까지 지정할 수 있습니다. 그 다음 오류관련 메세지를 기록하고 state를 지정합니다. 예제에서 state는 1이며 0~255까지 지정가능합니다.


'Programming > Microsoft SQL Server' 카테고리의 다른 글

[SQL Server] SQLCMD  (0) 2010.09.09
[SQL] 케이스(Case)  (0) 2010.09.07
[SQL] 예외처리(try ~ catch)  (0) 2010.09.06
[SQL] Batch처리(일괄처리)의 개념  (0) 2010.09.03
[SQL] Update  (0) 2010.09.01
[SQL] Replicate로 문자열 채워넣기  (0) 2010.08.26
0 0
1
블로그 이미지

클리엘