Exception Handling in C#

An exception is an error that occurs at runtime by your code. The C# language provides structured exception handling (SEH). In C#, exceptions are represented by classes. Exception is most base class, which can handle all types of exceptions. The .NET Framework has several built in exception classes as example DivideByZeroException, SQLException, IndexOutOfRangeException etc.

C# exception handling is managed by try, catch, throw, and finally blocks.

The basic structure of try, catch, and finally block is as follows:

try
{
    .........
}
catch (<exceptionType> e)
{
    ...........
}
finally
{
    ..........
}

The try block

A try block contains code that requires cleanup operations or may throw an exception at runtime. You cannot write try block only. try block must be associated with at least one catch or finally block. try block can be nested also.

The catch Block

If exception occurs, then control directly jumps to catch block. According to the need of code you can associate more than one catch block with try block. If the code in a try block doesn’t throws an exception, then catch block will never execute. You must specify a catch type catch block as example catch (Exception e) { … } or a type derived from System.Exception. Always remember that if you are using more than one catch block associated with try block, then catch (Exception e) { … } must be the last block within catch hierarchy. Exception class is most base class regarding exception therefore this base class has ability to catch all type of exception. The CLR searches from top to bottom for a matching catch type while you use try, catch block for exception handling.

The finally Block

In the try block, exception occur or may not occur, it is guaranteed that finally block will execute. It contains code that’s guaranteed to execute. You should write all the cleanup operation code in finally block. Suppose that you have written code for opening database connection in try block, then you should close the connection in try block. If you have written the code in finally block for closing the connection, then connection must be close.

Example

using System;
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[ ] args)
        {
            int[ ] intArr = new int[5];
            try
            {
                Console.WriteLine("Try block started.");
                // Below code will generate an index out-of-bounds exception.
                for (int i = 0; i < 8; i++)
                {
                    intArr[i] = i;
                    Console.WriteLine("arr[{0}]: {1}", i, intArr[i]);
                }
                Console.WriteLine("Exception occured, this won't be displayed");
            }
            catch (IndexOutOfRangeException e)
            {
                // Catch the exception.
                Console.WriteLine("\n ERROR :"+e.Message);
                Console.WriteLine("\n SOURCE :" + e.Source);               
            }
           finally
            {
                Console.WriteLine("Finally block.");
            }
            Console.WriteLine("After finally block.");
            Console.ReadLine();
        }
    }
}


In the given example, intArr is an int array of five elements. The for loop tries to execute eight time and also tries to insert element in intArr from 0 to 8, which causes an IndexOutOfRangeException to occur when an index value of 5 is tried.

Execute the above program, you will get the following output.

Output:
Try block started.
arr[0]: 0
arr[1]: 1
arr[2]: 2
arr[3]: 3
arr[4]: 4
ERROR : Index was outside the bounds of the array.
SOURCE : ConsoleApplication1
Finally block.
After finally block.

Using multiple catch Clauses

You can associate more than one catch clause with a try. Each catch must catch a different type of exception.

using System;
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            int [ ] firstArr = { 3,9,18,36,72,144,288,576 };
            int [ ] secondArr = { 3, 0, 6, 6, 0, 9 };
            for (int i = 0; i < firstArr.Length; i++)
            {
                try
                {
                    Console.WriteLine(firstArr[i] + " / " +
                    secondArr[i] + " is " +
                    firstArr[i] / secondArr[i]);
                }
                catch (DivideByZeroException e)
                {
                    Console.WriteLine("ERROR : "+e.Message);
                }
                catch (IndexOutOfRangeException e)
                {
                    Console.WriteLine("ERROR : " + e.Message);
                }
               
            }
                 Console.ReadLine();
        }
    }
}


Output:
3 / 3 is 1
ERROR : Attempted to divide by zero.
18 / 6 is 3
36 / 6 is 6
ERROR : Attempted to divide by zero.
144 / 9 is 16
ERROR : Index was outside the bounds of the array.
ERROR : Index was outside the bounds of the array.


It is not compulsory to associate multiple catch block with try block. You can write single catch block that will catch all type of exception.

catch(Exception e)
{
    // Your code here.
}

Nested try block

The try block within a try block is known as nested try block.

Example

using System;
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            int x = 100;
            int y = 0;
            try
            {                
                Console.WriteLine("Outer try block");
                try
                {
                    Console.WriteLine("First inner try block");
                    int z = x / y;
                }
                catch (ArithmeticException e)
                {
                    Console.WriteLine("Error from first inner try block");
                    Console.WriteLine("ERROR : "+e.Message);
                }
                try
                {
                    int[] a = new int[3];
                    a[3] = 40;
                }
                catch (IndexOutOfRangeException e)
                {
                    Console.WriteLine ("Error from second inner try block");
                    Console.WriteLine ("ERROR : " + e.Message);
                }                
            }
            catch (Exception e)
            {
                Console.WriteLine ("Error from outer try block");
            }
            Console.WriteLine ("Control outside the main try block");
            Console.ReadLine ();
        }        
    }
}


Output:
Outer try block
First inner try block
Error from first inner try block
ERROR : Attempted to divide by zero.
Error from second inner try block
ERROR : Index was outside the bounds of the array.
Control outside the main try block

In the above example, exceptions are handled by the inner try block. Nested try blocks can be used to handle different types errors in different ways.

Custom exception class

C# has already a lot of in-built exception classes to handle different types of errors but still sometime we need our own custom exception class to handle errors.  Now we will see how to create our exception class.

For implementing Custom Exception Handling, we need to derive our class from Exception base class.

using System;
namespace ConsoleApplication1
{
    public class CustomException : Exception
    {
        //Throw exception with out message
        public CustomException()
        {
            Console.WriteLine("Divide by zero exception occured");
        }
        //Throw exception with simple message
        public CustomException(string message)
            : base(message)
        {
            //put your custom code here
        }            
    }
    class Program
    {       
        static void Main(string[] args)
        {            
            try
            {
               Console.WriteLine("Eneter the integer value");
               int x = Convert.ToInt32(Console.ReadLine());
               Console.WriteLine("Eneter the divisior");
               int y = Convert.ToInt32(Console.ReadLine()); ;
               if(y==0)
               {
                   throw new CustomException();
               }
               else
               {
                    int z = x / y;
                    Console.WriteLine ("Division of {0} / {1} is = {2}", x,y,z);
               }                
            }
            catch (CustomException ex)
            {
                Console.WriteLine ("Error found in application:" + ex.Message);
            }           
            Console.ReadLine ();
        }        
    }
}


Key things about exception handling

  • try, catch and finally blocks are used to handle exceptions in C#.
  • The try block must be followed by a catch or finally block or both. You cannot use only try block.
  • catch {..} and catch(Exception ex){ }, both cannot be used simultaneously.
  • A multiple catch block is allowed with different exception types.
  • General catch {…….} or Exception ex){………. }, block must come last.
  • The finally block must come after the try or catch block.
  • The finally block will always executed, whether an exception occurred or not.
  • The finally block is used to write cleanup code. It is appropriate place for disposing objects.
  • The finally block cannot have a return or break statements because it isn't allow to leave the control.
  • C# allowed nested try-catch blocks.