Signup/Sign In
LAST UPDATED: DECEMBER 2, 2019

C# Exception Handling

    The objective of this article is to understand the concept of exception handling in C# programming language. An exception is an error that occurs at runtime of the program's execution. These runtime errors are unexpected situations that interrupt the normal flow of the program/application. For example: divide by zero exception, file not found exception, class not found exception, etc. So, this article will help you to understand how to deal with such unexpected situations using the exception handling.


    Introduction to C# Exception Handling

    Exception handling is the feature that provides a way to transfer control from one block of code to another when an unexpected error/situation arises. Every time we can't check where a program threw an error, hence exception handling comes into the picture. Through this feature, we can avoid the unexpected termination of a program. The try block monitors the exception that may occur at runtime, and if the exception occurs, then it is raised/thrown. The catch block handles the exception, which is raised/thrown from within the try block. We can't have only a catch block without a try block, which means both blocks work together to handle the exception. The try block must be followed by a single or the multiple catch block(s). We can also have a nested try and catch blocks.




    The Anatomy of C# Exceptions

    1. try - A try block is used to contain a piece of code from which the outcome of an exception is possible. If an exception occurs in the try block code, then the exception will be handled by the corresponding catch block.

    2. catch - A catch block is used to handle an exception thrown from the try block.

    3. finally - The finally block is used to execute certain instructions, whether an exception is thrown or not. It is useful when one wants to close the database connection, file stream, etc. that were opened inside the try block.

    4. throw - The throw keyword is used to create a new exception. It can be used in the catch block to re-throw an exception handled in the catch block.

    The syntax for exception handling is shown here:

    try
    {
          // statements due to which exception may arise
    }
    catch()
    {
          // exception handling code
    }
    catch()
    {
          // exception handling code
    }
    finally
    {
          // finally block statements always get executed
          // this is to perform some final task like DB connection close etc.
    }
    

    Let's take an example of divide by zero which leads to an exception,

    Filename: Program.cs

    using System;
    
    namespace Studytonight
    {
        public class Program
        {
            public static void Main(string[] args)
            {
                int num1 = 10;
                int num2 = 0;
                int result = num1/num2;
                Console.WriteLine(result);
                Console.WriteLine("Execution terminated at previous line");
            }
        }
    }

    Output:

    Run-time exception (line 11): Attempted to divide by zero.
    
    Stack Trace:
    
    [System.DivideByZeroException: Attempted to divide by zero.]
       at Studytonight.Program.Main(String[] args) :line 11

    In the above example, we tried to divide a number by zero and faced the unhandled divide by zero exception. In the next example, we will see how to handle such kind of runtime exception using the try and catch block.




    List of Exceptions and Overview

    The C# exceptions are represented by classes. All the exception classes must be derived from System.Exception class where System is a namespace and Exception is built-in exception class. Exceptions can be raised manually/explicitly by using the throw keyword and can be generated by the .NET Framework, by the common language runtime (CLR), or by application code. Following is the list of exceptions that are commonly seen.

    Exception Description
    ArgumentException The exception occurs when invalid arguments provided to a method
    ArgumentNullException The exception occurs when a method requires the argument and no argument provided
    FormatException The exception occurs when the format of an argument is invalid
    FileNotFoundException This exception occurs when access to a file provided and file is not present in the disk or at the specified path
    IOException The exception is thrown when an input/output error occurs
    IndexOutOfRangeException The exception occurs when the elements of an array or collection with an index outside its bounds
    DivideByZeroException The exception occurs when a number divide by zero
    SystemException This is the base class for system exceptions namespace



    Time for Examples!

    Let's take an example of divide by zero with try and catch blocks

    Filename: Program.cs

    using System;
    
    namespace Studytonight
    {
        public class Program
        {
            public static void Main(string[] args)
            {
                try
                {
                    int num1 = 10;
                    int num2 = 0;
                    int result = num1/num2;
                    Console.WriteLine(result);
                }
                // catch the DivideByZeroException exception
                catch(DivideByZeroException)
                {
                    Console.WriteLine("Divide by zero exception");
                }
                // catch all other exceptions
                catch(Exception e)
                {
                    Console.WriteLine("Exception caught: "+e);
                }
            }
        }
    }

    Output:

    Divide by zero exception

    In the above example, we have used a single try block with multiple catch blocks. If you closely observe the first catch block, in it we specified the known exception which got handled. Hence, the second catch block didn't got executed. If we don't know which exceptions are going to occur, then we specify an object of Exception type in the catch clause and use that object to recognize which exception was occurred, because all the exception classes in C# are derived from the Exception class.

    Let's take an example with nested try and catch and finally block.

    Filename: Program.cs

    using System;
    
    namespace Studytonight
    {
        public class Program
        {
            public static void Main(string[] args)
            {
                try
                {
                    try
                    {
                        int num1 = 10;
                        int num2 = 0;
                        int result = num1/num2;
                        Console.WriteLine(result);
                    }
                    catch(DivideByZeroException e)
                    {
                        Console.WriteLine(e.Message);
                    }
                    
                    int[] arr = {10,20,30};
                    Console.WriteLine(arr[10]);
                }
                catch(Exception e)
                {
                    Console.WriteLine("Exception caught: "+e);
                }
                finally
                {
                    Console.WriteLine("Finally block executed");
                }
            }
        }
    }

    Output:

    Attempted to divide by zero.
    Exception caught: System.IndexOutOfRangeException: Index was outside the bounds of the array.
    Finally block executed

    In the above example, we have used nested try and catch blocks. When the divide by zero exception occurs in the try block, then the corresponding catch block gets executed and the Message property describes the current exception. Thus, the message attempted to divide by zero is printed on the console. On the other side, when we don't know which exception is going to occur, then create an object of exception type in catch clause and use that object to recognize which exception occurred. In our case, we also get the index is out of array bounds exception caused due to arr[10], because only three elements are present in the array. At last, we have used the finally block, which is always executed whether an exception is thrown or not.

    Let's take a simple example for throw keyword.

    Filename: Program.cs

    using System;
    
    namespace Studytonight
    {
        public class Program
        {
            public static void Main(string[] args)
            {
                string s = null;
                if(string.IsNullOrEmpty(s))
                {
                    throw new NullReferenceException("String is null");
                }
            }
        }
    }

    Output:

    Run-time exception (line 12): String is null
    
    Stack Trace:
    
    [System.NullReferenceException: String is null]
       at Studytonight.Program.Main(String[] args) :line 12

    In the above example, we have created a new exception using the throw keyword and we used the new keyword in the throw statement to create an object of the valid exception type. The if block will always execute as the string s is null.




    C# User-Defined Exceptions

    The C# programming language allows us to create custom exception classes and to create a user-defined exception class, we need to inherit the Exception class in it. The following example demonstrates how to define a custom exception class by inheriting the Exception class.

    Filename: Program.cs

    using System;
    namespace Studytonight
    {
        public class CustomException:Exception
        {
            public CustomException(string s):base(s)
            {
                // do something
            }
        }
        public class Program
        {
            public static void Main(string[] args)
            {
                try
                {
                    string s = null;
                    if(string.IsNullOrEmpty(s))
                    {
                        throw new CustomException("String is null");
                    }
                }
                catch(CustomException ce)
                {
                    Console.WriteLine(ce.Message);
                }
            }
        }
    }

    Output:

    String is null

    In the above example, we have inherited the Exception class into our user-defined exception class CustomException. As we know, the if block will always be executed as the string s is null, and using the throw statement, we raised our CustomException to throw an exception. Here, the CustomException is a derived class. Hence, the base keyword is used to access members of the base class from within a derived class.




    Conclusion:

    We hope this article helped you to understand the exception handling in C# language. If you have any queries, then please let us know in the comment section. We are happy to solve your doubts.

    Subject Matter Expert of C# Programming at Studytonight.
    IF YOU LIKE IT, THEN SHARE IT
    Advertisement

    RELATED POSTS