C#의 에러 종류
.NET Framework에서 소스코드를 작성하고 프로그램을 실행할 때, 컴파일 에러 또는 런타임 에러가 발생할 수 있습니다.
컴파일 에러
소스코드를 컴파일 시 발생하는 에러를 컴파일 에러 또는 컴파일 타임 에러라고 말합니다. 컴파일 에러는 주로 구문 오류로 발생합니다.
큰 따옴표 및 세미콜론을 누락하거나, 변수에 타입과 다른 값을 할당하거나, 키워드 철자를 잘못 입력하거나, 추상 클래스 및 인터페이스에 대한 객체를 생성하려고 시도하는 등 다양한 이유로 컴파일 에러가 발생합니다.
컴파일 에러는 프로그램이 만들어지기 전에 발생하며, Visual Studio와 같은 개발 툴에서 에러 내용을 확인할 수 있으므로 프로그램 실행 전에 수정할 수 있습니다.
런타임 에러
프로그램 실행 시 발생하는 에러를 런타임 에러라고 말합니다. 컴파일 에러는 프로그램 실행 전 발생하는 에러이며, 런타임 에러는 프로그램 실행 후 발생하는 에러입니다.
프로그램에서 잘못된 데이터를 입력하거나, 도중에 네트워크가 끊기거나, 메모리 부족 등의 경우 런타임 에러가 발생합니다.
프로그램에서 런타임 에러가 발생하면 프로그램이 비정상적으로 종료되므로 상당히 치명적입니다.
아래에서 자주 언급될 예외는 런타임 에러와 동일한 개념으로 이해하면 쉽습니다.
예외의 종류
예외 클래스의 객체는 런타임 에러(예외)가 발생할 때마다 프로그램의 비정상적인 종료를 담당합니다. 예외 클래스는 BCL(Base Class Libraries)에 정의되어 있으며, 다음과 같은 예외 종류마다 별도의 클래스를 제공합니다.
IndexOutOfRangeException: 배열의 범위를 벗어나는 경우
FormatException: 주로 문자열을 다른 타입으로 변환하는 과정에서 발생
NullReferenceException: null로 초기화된 객체를 접근하는 경우
DividebyZeroException: 0으로 나눔
FileNotFoundException: 파일을 찾을 수 없는데 파일을 접근하는 경우
SQLExceipton: Database에서 에러가 발생하는 경우
OverflowException: 데이터 타입이 표현할 수 있는 범위를 벗어나는 경우
등...
이러한 예외 클래스는 특정 예외 에러 메시지를 제공합니다. 즉, 프로그램이 비정상적으로 종료 후 어떠한 이유로 종료되었는지 에러 메시지를 제공합니다.
예제 1. 0으로 나눔
정수를 0으로 나누는 것은 불가능하므로 C#에서 DivideByZeroException이 발생합니다. 다음 예제는 정수를 0으로 나누었을 때 결과를 보여줍니다.
class Program
{
static void Main(string[] args)
{
int a = 20;
int b = 0;
int result = 0;
Console.WriteLine("o으로 나누기 전");
result = a / b;
Console.WriteLine("o으로 나눈 후");
}
}
에러 내용
변수 num을 정수 0으로 나누었기 때문에 CLR은 DivideByZeroException을 발생시켜 프로그램 실행을 종료합니다. CLR은 소스코드를 프로그램으로 만드는 역할이라고 이해하면 됩니다.(이번 포스팅에서 CLR에 대해 설명하지 않습니다.)
예외 처리가 필요한 이유
위 예제처럼 예외가 발생하는 경우 프로그램을 사용하는 고객 입장에서는 어떠한 문제가 발생했는지 이해할 수 없습니다. 따라서 CLR이 예외를 발생시키는 경우 프로그래머는 예외 메시지를 사용자가 이해할 수 있는 메시지로 변환하고 예외를 catch 할 수 있는 소스코드를 작성해야 합니다.
예외를 처리함으로써 다음과 같은 이점을 얻을 수 있습니다.
1. 프로그램의 비정상적인 종료를 막을 수 있습니다.
2. 사용자에게 친숙한 에러 메시지를 표시할 수 있습니다.
예외 처리 방법
.NET Framework에서 예외를 처리하는 방법은 소스코드를 논리적으로 작성하는 방법과 try-catch문을 사용하는 방법이 있습니다.
예외 처리 예제 1. 논리적
다음 예제는 소스코드를 논리적으로 작성하여 예외를 처리합니다. 변수 b가 0이 아닌 경우 나누기 연산을 수행합니다.
class Program
{
static void Main(string[] args)
{
int a = 20;
int b = 0;
int result = 0;
Console.WriteLine("o으로 나누기 전");
if(b != 0)
{
result = a / b;
}
Console.WriteLine("o으로 나눈 후");
}
}
실행 결과
o으로 나누기 전
o으로 나눈 후
하지만, 소스코드를 논리적으로 작성하는 것은 한계가 있으며 오히려 소스코드를 지저분하게 만들 수 있습니다. 아래에서 소개되는 try-catch문을 사용하여 예외를 처리하는 것이 좋습니다.
try-catch문
try-catch문을 구현하기 위해 .NET Fraomework는 세 가지 키워드를 제공합니다.
1. try
try 키워드는 예외가 발생할 수 있는 소스코드를 작성해야 하는 블록을 설정합니다. 즉, 예외가 발생할 수 있는 소스코드를 try 블록 내부에 작성합니다.
2. catch
catch 키워드는 try 블록에서 발생한 예외를 잡기 위해 사용됩니다. catch 된 예외에 대해 필요한 조치를 취하는 소스코드를 작성합니다.
3. finally
finally 키워드는 try 블록에서 소스코드가 정상적으로 실행되어 catch문이 실행되지 않거나 catch문이 실행되더라도 항상 실행해야 하는 소스코드를 작성합니다.
try-catch 구문
다음 소스코드는 C#에서 예외를 처리하는 구문을 보여줍니다. try 블록에 대해 여러 개의 catch 블록을 작성할 수 있습니다.
try
{
// 예외가 발생할 수 있는 소스코드를 작성합니다.
}
catch(DivideByZeroException ex1)
{
// try문에서 정수를 0으로 나누었을 경우 실행되는 catch문입니다.
}
catch(FormatException ex2)
{
// try문에서 문자열이 비정상적으로 변환되었을 경우 실행되는 catch문입니다.
}
finally
{
// 예외와 상관없이 항상 실행되어야하는 소스코드를 작성합니다.
}
try-catch 예제
다음 예제는 Console에서 두 개의 값을 입력받아 두 개의 값을 나누는 소스코드입니다.
class Program
{
static void Main(string[] args)
{
int a, b, c;
try
{
a = int.Parse(Console.ReadLine());
b = int.Parse(Console.ReadLine());
c = a / b;
Console.WriteLine("C VALUE = " + c);
}
catch
{
Console.WriteLine("에러 발생....");
}
}
}
실행 결과 1. 100과 0 입력
100
0
에러 발생....
실행 결과 2. 100과 hi 입력
100
hi
에러 발생....
위 예제는 catch 문에 특정 예외 클래스를 명시하지 않았으므로 모든 종류의 예외를 catch 합니다.
다음 예제는 0으로 입력하는 경우와 문자열을 입력하는 경우 catch문에 예외 클래스를 명시하여 세부적으로 처리합니다.
class Program
{
static void Main(string[] args)
{
int a, b, c;
try
{
a = int.Parse(Console.ReadLine());
b = int.Parse(Console.ReadLine());
c = a / b;
Console.WriteLine("C VALUE = " + c);
}
catch(DivideByZeroException ex1) // 0으로 나누는 경우
{
Console.WriteLine("0으로 나눌 수 없습니다.");
}
catch (FormatException ex2) // 문자열을 입력하는 경우
{
Console.WriteLine("문자열을 숫자로 변환할 수 없습니다.");
}
}
}
실행 결과 1. 100과 0 입력
100
0
0으로 나눌 수 없습니다.
실행 결과 2. 100과 hi 입력
100
hi
문자열을 숫자로 변환할 수 없습니다.
예외 클래스의 프로퍼티
C#의 예외 클래스에는 다음 세 가지 프로퍼티가 존재합니다.
1. Message
Message 프로퍼티에는 예외가 발생한 이유가 할당됩니다.
2. Source
Source 프로퍼티에는 예외가 발생한 응용 프로그램의 이름이 할당됩니다.
3. HelpLink
HelpLink 프로퍼티는 예외가 발생했을 때 사용자에게 유용한 정보를 제공합니다.
예외 클래스의 프로퍼티 예제
다음 예제는 catch문에서 예외 클래스의 프로퍼티 값을 콘솔에 출력합니다.
class Program
{
static void Main(string[] args)
{
int a, b, c;
try
{
a = int.Parse(Console.ReadLine());
b = int.Parse(Console.ReadLine());
c = a / b;
Console.WriteLine("C VALUE = " + c);
}
catch(DivideByZeroException ex1)
{
Console.WriteLine(ex1.Message);
Console.WriteLine(ex1.Source);
Console.WriteLine(ex1.HelpLink);
}
catch (FormatException ex2)
{
Console.WriteLine(ex2.Message);
Console.WriteLine(ex2.Source);
Console.WriteLine(ex2.HelpLink);
}
}
}
실행 결과 1.100과 0 입력
100
0
Attempted to divide by zero.
CSharpProgramming
실행 결과 2. 100과 hi 입력
100
hi
Input string was not in a correct format.
System.Private.CoreLib
정리
- .NET Framework에서 에러는 컴파일 에러와 런타임 에러로 분류됩니다.
- 런타임 에러는 예외와 동일한 개념으로 프로그램 실행 중 발생한 에러입니다.
- 예외를 처리하는 방법으로 소스코드를 논리적으로 작성하는 방법과 try-catch문이 존재합니다.
'C#' 카테고리의 다른 글
[C#]finally 키워드, finally문 (0) | 2022.06.26 |
---|---|
[C#]다중 catch문, 다중 예외 처리 (0) | 2022.06.26 |
[C#]타입 변환 및 타입 캐스팅(Type Conversion and Type Casting) (0) | 2022.06.21 |
[C#]스레드 Join 메서드(Join Method of Thread) (0) | 2022.06.15 |
[C#]스레드 상태 확인 (0) | 2022.06.06 |
댓글