C# provides built-in support for handling anomalous situations, known as exceptions, which may occur during the execution of your program. These exceptions are handled by code that is outside the normal flow of control.
Exception handling is a way to handle errors at runtime that cause application termination.
.NET supports structured exception handling with the help of try, catch, finally and throw key words.
C# provides following keywords to handle an exception.
The try block
The code, which seems to generate an exception, is placed under the try block. When an exception occurs in the try section, code compilation is transferred to the catch section.
try
{
//Code that may cause an exception
}
A try block should have at least one catch or finally block. We can use both catch and finally block after the try block.
Remember there should be no other code between these blocks.
In the above code if no errors or errors are found, the flow of execution goes to the third block finally. If an exception is thrown execution goes to a catch block.
Exception Nesting
You can create an exception inside of another. This is referred to as nesting an exception.
To nest an exception, write a try block in the body of the parent exception. The nested try block must be followed by its own catch(es) clause.
The catch block
In this block you implement methods for dealing with any possible errors of the try block. At the end of this block execution continues to the last code block.
When an exception occurs in the try section, code compilation is transferred to the catch block.
try
{
//Code that may cause an exception
}
catch (...)
{
//Code for handling errors
}
The catch block should be immediately placed after try block.
The following program shows the catch block:
using System;
namespace exception_example1
{
class Program
{
static void Main(string[] args)
{
try
{
int i, k = 0, j;
Console.Write("Enter a number one: ");
i = Convert.ToInt32(Console.ReadLine());
Console.Write("Enter a number two: ");
j = Convert.ToInt32(Console.ReadLine());
k = i / j;
Console.WriteLine("Output of division : {0}", k);
Console.ReadKey();
}
catch (DivideByZeroException ex)
{
Console.WriteLine(ex.Message);
Console.ReadKey();
}
}
}
}
In the above program if you input the second number as zero (0) it will generate DivideByZeroException.
The catch statement of the catch block takes an object of the exception class as a parameter, which refers to the raised exception. When the exception is caught, the statements within the catch blocks are executed.
One of the properties of the Exception class is called Message. This property contains a string that describes the type of error that occurred. You can then access this Exception.Message property to display an error message if you want.
You can have multiple catch blocks after the try block. See the code below:
using System;
namespace exceptionHandling_example3
{
class Program
{
static void Main(string[] args)
{
double Operand1, Operand2;
double Result = 0.00;
char Operator;
Console.WriteLine("This program allows you to perform an operation on two numbers");
try
{
Console.Write("Enter a number: ");
Operand1 = double.Parse(Console.ReadLine());
Console.Write("Enter an operator: ");
Operator = char.Parse(Console.ReadLine());
Console.Write("Enter a number: ");
Operand2 = double.Parse(Console.ReadLine());
if (Operator != '+' &&
Operator != '-' &&
Operator != '*' &&
Operator != '/')
throw new Exception(Operator.ToString());
if (Operator == '/') if (Operand2 == 0)
throw new DivideByZeroException("Division by zero is not allowed");
switch (Operator)
{
case '+':
Result = Operand1 + Operand2;
break;
case '-':
Result = Operand1 - Operand2;
break;
case '*':
Result = Operand1 * Operand2;
break;
case '/':
Result = Operand1 / Operand2;
break;
default:
Console.WriteLine("Bad Operation");
break;
}
Console.WriteLine("\n{0} {1} {2} = {3}", Operand1, Operator, Operand2, Result);
}
catch (DivideByZeroException ex)
{
Console.WriteLine(ex.Message);
}
catch (Exception ex)
{
Console.WriteLine("\nOperation Error: {0} is not a valid operator", ex.Message);
}
Console.ReadKey();
}
}
}
The finally block
The finally block is executed whether or not an exception was thrown.
try
{
//Code that may cause an exception
}
catch (...)
{
//Code for handling exception
}
finally
{
//clean up code
}
The catch block is used to handle exceptions that occur in a try block. The finally block is used to guarantee the execution of statements, regardless of whether an exception has occurred or not.
See the code to understand finally block
using System;
namespace exception_example1
{
class Program
{
static void Main(string[] args)
{
int i, k = 0, j;
try
{
Console.Write("Enter a number one: ");
i = Convert.ToInt32(Console.ReadLine());
Console.Write("Enter a number two: ");
j = Convert.ToInt32(Console.ReadLine());
k = i / j;
}
catch (DivideByZeroException ex)
{
Console.WriteLine(ex.Message);
Console.ReadKey();
}
finally
{
Console.WriteLine("Output of division : {0}", k);
Console.ReadKey();
}
}
}
}
Points about finally block
-
You can have only one finally block for each try block.
-
It is not mandatory to have a finally block after a try block.
-
The finally block is used to do all the clean up code.
-
It does not support the error message, but all the code contained in the finally block is executed after the exception is raised.
To cover unmanaged resource we use finally block. For example when we are not able to find file/database exception we close the file.
It is used for cleaning up resources that your program might have used and generic code that should always be executed.
Exceptions and Custom Messages
Sometimes, the message provided by the Exception class may not be clear to the normal users. As an alternative, you can create your own message and display it to the user.
You can display the exception message along with the user defined custom message. See the program below.
using System;
namespace exceptionHandeling_Example2
{
class Program
{
static void Main(string[] args)
{
int num1, num2, sum;
try
{
Console.Write("Enter first number : ");
num1 = int.Parse(Console.ReadLine());
Console.Write("Enter second number : ");
num2 = int.Parse(Console.ReadLine());
sum = num1 + num2;
Console.WriteLine(sum);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
Console.WriteLine("The error indicates that the input was not provided" +
"in the desired format, You might have provide input not as integer");
}
Console.ReadKey();
}
}
}
Throwing an Exception
Exceptions can be explicitly generated by a program using the throw keyword.
Exceptions are used to indicate that an error has occurred while running the program. Exception objects that describe an error are created and then thrown with the throw keyword. The runtime then searches for the most compatible exception handler.
using System;
namespace exceptionHandling_example4
{
class Program
{
static void Main(string[] args)
{
int total = 0;
int[] arr = new int[10] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
try
{
for (int i = 0; i <= 10; i++)
{
total += arr[i];
}
throw new System.Exception();
}
catch(Exception ex)
{
Console.WriteLine("Unknown error");
Console.ReadLine();
}
}
}
}
We should not throw exception as it is not good practice of programing. We should try to handle it in a more better manner.
I will be explaining more about exception handling and how to throw exception in my coming articles.
The Exception Class
To support exception handling, the .NET Framework provides a special class called Exception. Once the compiler encounters an error, the Exception class allows you to identify the type of error and take an appropriate action.
Normally, Exception mostly serves as the general class of exceptions. Anticipating various types of problems that can occur in a program, Microsoft derived various classes from Exception to make this issue friendlier.
As a result, almost any type of exception you may encounter already has a class created to deal with it. Therefore, when your program faces an exception, you can easily identify the type of error.
Exceptions are of two types:
-
SystemException
-
ApplicationException
There are many exception classes, which are directly or indirectly derived from the System.Exception class. Some of the exception classes derived from the System.Exception class are System.System.Exception and System.ApplicationException.
The Hierarchy of Exception Class
SystemException: These exceptions are defined and the common language runtime throws SystemException. The System.System.Exception acts as a base class for all predefined exception.
ApplicationException: These exceptions are not defined. The ApplicationException is thrown by a user program rather than the runtime. They are non-fatal error. If any user-defined application requires its own exception, it should inherit the exception from the System.ApplicationException class.
Following are some common exception classes.
Exception Class |
Causes |
SystemException |
A failed run-time checks; used as a base class for other. |
AccessException |
Failure to access a type member, such as a method or field. |
ArgumentException |
An argument to a method was invalid. |
ArgumentNullException |
A null argument was passed to a method that doesn't accept it. |
ArgumentOutOfRangeException |
Argument value is out of range. |
ArithmeticException |
Arithmetic over - or underflow has occurred. |
ArrayTypeMismatchException |
Attempt to store the wrong type of object in an array. |
BadImageFormatException |
Image is in the wrong format. |
CoreException |
Base class for exceptions thrown by the runtime. |
DivideByZeroException |
An attempt was made to divide by zero. |
FormatException |
The format of an argument is wrong. |
IndexOutOfRangeException |
An array index is out of bounds. |
InvalidCastExpression |
An attempt was made to cast to an invalid class. |
InvalidOperationException |
A method was called at an invalid time. |
MissingMemberException |
An invalid version of a DLL was accessed. |
NotFiniteNumberException |
A number is not valid. |
NotSupportedException |
Indicates that a class does not implement a method. |
NullReferenceException |
Attempt to use an unassigned reference. |
OutOfMemoryException |
Not enough memory to continue execution. |
StackOverflowException |
A stack has overflown. |