A. try ~ catch문
static void Main(string[] args)
{
int[] arr = { 1, 2, 3 };
try
{
for (int i = 0; i < 5; i++)
Console.WriteLine(arr[i]);
}
catch(IndexOutOfRangeException e)
{
Console.WriteLine($"예외가 발생했습니다 :{e.Message}");
}
Console.WriteLine("종료");
}
B. System.Exception 클래스
C#에서 모든 예외클래스는 System.Exception 클래스로부터 파생되었다.
즉, catch절에서 Exception으로 모든 예외를 다 받아낼 수 있다.
* 하지만, 예외 상황에 따라 섬세한 예외 처리가 필요한 코드에서는 Exception 클래스만으로는 대응이 어려우니 무조건 Exception클래스를 사용하는 것은 금물. (처리하지 않아야 할 예외까지 처리하게되므로 버그 발생요인이된다.)
C. 예외 던지기
1. 메소드안에서 throw 하고 호출하는 try catch문에서 받아내는경우
static void DoSomething(int arg)
{
if(arg<10)
Console.WriteLine($"arg : {arg}");
else
throw.new Exception("arg가 10보다 큽니다.");
}
static void Main()
{
try
{
DoSomething(13);
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
}
2. 식(Expression)으로 예외처리하는경우
Throw는 보통 문(statement)로 처리하지만, C# 7.0부터는 식(expression)으로도 사용할 수 있도록 개선되었다.
static void Main(string[] args)
{
try
{
int? a = null;
int b = a ?? throw new ArgumentNullException(); // a==null이면 a리턴, a!=null 이면 throw리턴
}
catch(ArgumentNullException e)
{
Console.WriteLine(e);
}
try
{
int[] array = new[] { 1, 2, 3 };
int index = 4;
int value = array[index >= 0 && index < 3 ? index : throw new IndexOutOfRangeException()];
}
catch (IndexOutOfRangeException e)
{
Console.WriteLine(e);
}
}
D. try~catch 와 finally
try블록에서 코드를 실행하다 예외가 던져지면 catch절로 바로 넘어가므로 try블록의 자원해제같은 중요코드를 실행하지 못하게되므로 버그를 만드는 원인이된다. 예를들어 try블록 끝의 DB 커넥션을 못닫게되면 사용할 수 있는 커넥션이 점점줄어서 DB에 연결할수 없는 상황이 생긴다.
이런 상황을 해결하기위해 finally 절을 사용해서 뒷정리 코드를 넣는다.
static int Divide(int divisor, int dividend)
{
try
{
Console.WriteLine("Divide() 시작");
return divisor / dividend;
}
catch(DivideByZeryException e)
{
throw e;
}
finally
{
Console.WriteLine("Divide() 끝");
}
}
* finally 안에서도 예외가 발생할수있으므로, 예외가 일어나지않는다고 100% 확신이 없으면 try~catch 블록을 한번더 사용한다.
E. 사용자 정의 예외 클래스 만들기
특별한 데이터를 담아서 예외 처리 루틴에 추가정보를 제공하는 경우나, 예외상황을 더 잘 설명하고싶은경우에 사용자 정의 예외 클래스가 필요하다. 이 때, C#의 모든 예외는 Exception클래스를 상속받아야 한다.
class InvalidArgumentException : Exception
{
public InvalidArgumentException()
{
}
public InvalidArgumentException(string message) : base(message)
{
}
}
F. 예외 필터(Exception Filter)하기
C#6.0 부터는 catch절이 받아들일 예외 객체에 제약 사항을 명시하여 해당 조건을 만족하는 예외 객체에 대해서만 예외처리코드를 실행할 수 있게하는 예외 필터(Exception Filter)가 도입되었다.
catch() 문 뒤에 when 키워드를 이용해서 제약조건을 기술하면된다. (when을 if라고 생각하면된다.)
class FilterableException : Exception
{
public int ErrorNo { get; set; }
}
class MainApp
{
static void Main(string[] args)
{
Console.WriteLine("Enter Number Between 0-10");
string input = Console.ReadLine();
try
{
int num = Int32.Parse(input);
if (num < 0 || num > 10)
throw new FilterableException() { ErrorNo = num };
else
Console.WriteLine($"Output : {num}");
}
catch(FilterableException e) when (e.ErrorNo<0) //ErrorNo 프로퍼티가 0미만인 경우만 catch하도록 예외 필터하기
{
Console.WriteLine("Negative input is not allowed");
}
catch(FilterableException e)when (e.ErrorNo>10) //ErrorNo 프로퍼티가 10초과인 경우만 catch하도록 예외 필터하기
{
Console.WriteLine("Too big number is not allowed");
}
}
G. 예외 처리의 장점
1. 실제 일을하는 코드와 문제를 처리하는 코드를 분리시킴으로써 코드를 간결하게 만들어준다.
2. 예외 객체의 StackTrace 프로퍼티를 통해 문제가 발생한 코드의 위치를 알려주므로 디버깅에 용이하다.
catch(DevidedByZeryException e)
{
Console.WriteLine(e.StackTrace);
}
//실행결과
// 위치 : StackTrace.MainApp.Main(String[] args) 파일 : D:\StackTrace\MainApp.cs 줄 : 12
3. 문제점을 하나로 묶어내거나 코드에서 발생할 수 있는 오류를 종류별로 정리해주는 효과가있다. (가독성 up)
'C# 공부 > C# 기본 문법' 카테고리의 다른 글
대리자(Delegate)와 이벤트 - 2 (이벤트, 대리자와 이벤트의 차이) (0) | 2020.08.02 |
---|---|
대리자(Delegate)와 이벤트 - 1 (대리자, 대리자를 사용하는 이유와 상황, 일반화 대리자, 대리자 체인, 익명 메소드) (0) | 2020.08.01 |
일반화(Generic) 프로그래밍 (일반화 메소드/클래스, 형식매개변수 제약, 일반화 컬렉션) (1) | 2020.07.28 |
인덱서 (인덱서의 선언과 사용, foreach가 가능한 객체 만들기) (0) | 2020.07.26 |
컬렉션 (ArrayList, Queue, Stack, Hashtable) (0) | 2020.07.26 |