Skip to main content

Exceptions and Exception handling in C# Explained


Exceptions and Exception handling in C#

The C# language's exception handling features help you deal with any unexpected or exceptional situations that occur when a program is running. Exception handling uses the trycatch, and finally keywords to try actions that may not succeed, to handle failures when you decide that it is reasonable to do so, and to clean up resources afterward. Exceptions can be generated by the common language runtime (CLR), by the .NET Framework or any third-party libraries, or by application code. Exceptions are created by using the throw keyword.
In many cases, an exception may be thrown not by a method that your code has called directly, but by another method further down in the call stack. When this happens, the CLR will unwind the stack, looking for a method with a catch block for the specific exception type, and it will execute the first such catch block that is found. If it finds no appropriate catch block anywhere in the call stack, it will terminate the process and display a message to the user.
C# includes built-in classes for every possible exception. All the exception classes are directly or indirectly derived from the Exception class. There are two main classes for exceptions - SystemException and ApplicationException. SystemException is a base class for all CLR generated errors whereas ApplicationException serves as a base class for all application related exceptions, which you want to raise on business rule violation.
Exception Class Hierachy

Exception classes Hierarchy
As you can see in the above figure, SystemException class is a base class for all the exception that can occurs during execution of the program. No other class derives ApplicationException class by default, because you as a programmer need to derive this class to create your own exeception classes as per the business rules.

Important Exception Classes

The following table lists important exception classes available in .Net.
Exception Description
ArgumentException Raised when a non-null argument that is passed to a method is invalid.
ArgumentNullException Raised when null argument is passed to a method.
ArgumentOutOfRangeException Raised when the value of an argument is outside the range of valid values.
DivideByZeroException Raised when an integer value is divide by zero.
FileNotFoundException Raised when a physical file does not exist at the specified location.
FormatException Raised when a value is not in an appropriate format to be converted from a string by a conversion method such as Parse.
IndexOutOfRangeException Raised when an array index is outside the lower or upper bounds of an array or collection.
InvalidOperationException Raised when a method call is invalid in an object's current state.
InvalidCastException Raised when incompitible types are being converted.
KeyNotFoundException Raised when the specified key for accessing a member in a collection is not exists.
NotSupportedException Raised when a method or operation is not supported.
NullReferenceException Raised when program access members of null object.
OverflowException Raised when an arithmetic, casting, or conversion operation results in an overflow.
OutOfMemoryException Raised when a program does not get enough memory to execute the code.
StackOverflowException Raised when a stack in memory overflows.
TimeoutException The time interval allotted to an operation has expired.
Every exception class in .Net is derived from the base Exception class. It includes the following important properties using which you can use to get information about the exception when you handle the exception.

Property Description
Message Provides details about the cause of the exception.
StackTrace Provides information about where the error occurred.
InnerException Provides information about the series of exceptions that might have occurred.
HelpLink This property can hold the help URL for a particular exception.
Data This property can hold arbitrary data in key-value pairs.
TargetSite Provides the name of the method where this exception was thrown.

When an error occurs, either application code or the default handler handles the exception.

The Anatomy of C# Exceptions

Exceptions allow an application to transfer control from one part of the code to another. When an exception is thrown, the current flow of the code is interrupted and handed back to a parent try catch block. C# exception handling is done with the follow keywords: try, catch, finally, and throw
·         try – A try block is used to encapsulate a region of code. If any code throws an exception within that try block, the exception will be handled by the corresponding catch.
·         catch – When an exception occurs, the Catch block of code is executed. This is where you are able to handle the exception, log it, or ignore it.
·         finally – The finally block allows you to execute certain code if an exception is thrown or not. For example, disposing of an object that must be disposed of.
·         throw – The throw keyword is used to actually create a new exception that is the bubbled up to a try catch finally block.

C# try and catch

The try statement allows you to define a block of code to be tested for errors while it is being executed.
The catch statement allows you to define a block of code to be executed, if an error occurs in the try block.
The try and catch keywords come in pairs:

Syntax

    public static void Main()
    {
        try
        {
            //  Block of code to try
        }
        catch (Exception e)
        {
            //  Block of code to handle errors
        }
     }
Consider the following example, where we create an array of three integers:
The code snippet below will generate an error, because numArray[5] does not exist.

int[] numArray = { 1, 2, 3 };
        Console.WriteLine(numArray[5]); // error!

The error message will be something like shown below:

System.IndexOutOfRangeException: 'Index was outside the bounds of the array.'
If an error occurs, we can use try...catch to catch the error and execute some code to handle it.
In the following example, we use the variable inside the catch block (e) together with the built-in Message property, which outputs a message that describes the exception:
     public static void Main()
    {
        try
        {
            int[] myNumbers = { 1, 2, 3 };
            Console.WriteLine(myNumbers[5]);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
    }

Finally

The finally statement lets you execute code, after try...catch, regardless of the result:
    public static void Main()
    {
        try
        {
            int[] myNumbers = { 1, 2, 3 };
            Console.WriteLine(myNumbers[5]);
        }
        catch (Exception e)
        {
            Console.WriteLine("Something went wrong.");
        }
        finally
        {
            Console.WriteLine("The 'try catch' is finished.");
        }
    }

The throw keyword

The throw statement allows you to create a custom error.
The throw statement is used together with an exception class. There are many exception classes available in C#: ArithmeticExceptionFileNotFoundExceptionIndexOutOfRangeExceptionTimeOutException, etc:
 Example

static void checkAge(int age)
    {
        if (age < 18)
        {
   throw new ArithmeticException("Access denied - You must be at least 18 years old.");
        }
        else
        {
            Console.WriteLine("Access granted - You are old enough!");
        }
    }

Performance considerations

Throwing or handling an exception consumes a significant amount of system resources and execution time. Throw exceptions only to handle truly extraordinary conditions, not to handle predictable events or flow control. For example, in some cases, such as when you're developing a class library, it's reasonable to throw an exception if a method argument is invalid, because you expect your method to be called with valid parameters. An invalid method argument, if it is not the result of a usage error, means that something extraordinary has occurred. Conversely, do not throw an exception if user input is invalid, because you can expect users to occasionally enter invalid data. Instead, provide a retry mechanism so users can enter valid input. Nor should you use exceptions to handle usage errors. Instead, use assertions to identify and correct usage errors.
In addition, do not throw an exception when a return code is sufficient; do not convert a return code to an exception; and do not routinely catch an exception, ignore it, and then continue processing.

Re-throwing an exception

In many cases, an exception handler simply wants to pass the exception on to the caller. This most often occurs in:
·         A class library that in turn wraps calls to methods in the .NET Framework class library or other class libraries.
·         An application or library that encounters a fatal exception. The exception handler can log the exception and then re-throw the exception.
The recommended way to re-throw an exception is to simply use the throw statement in C# without including an expression. This ensures that all call stack information is preserved when the exception is propagated to the caller. The following example illustrates this. A string extension method, FindOccurrences, wraps one or more calls to String.IndexOf(String, Int32) without validating its arguments beforehand.

Example

using System;
using System.Collections.Generic;

public static class Library
{
    public static int[] FindOccurrences(this String s, String f)
    {
        var indexes = new List<int>();
        int currentIndex = 0;
        try
        {
            while (currentIndex >= 0 && currentIndex < s.Length)
            {
                currentIndex = s.IndexOf(f, currentIndex);
                if (currentIndex >= 0)
                {
                    indexes.Add(currentIndex);
                    currentIndex++;
                }
            }
        }
        catch (ArgumentNullException)
        {
            // Perform some action here, such as logging this exception.

            throw;
        }
        return indexes.ToArray();
    }
}

Caller

public class Example
{
    public static void Main()
    {
        String s = "It was a cold day when...";
        int[] indexes = s.FindOccurrences("a");
        ShowOccurrences(s, "a", indexes);
        Console.WriteLine();

        String toFind = null;
        try
        {
            indexes = s.FindOccurrences(toFind);
            ShowOccurrences(s, toFind, indexes);
        }
        catch (ArgumentNullException e)
        {
            Console.WriteLine("An exception ({0}) occurred.",
                              e.GetType().Name);
            Console.WriteLine("Message:\n   {0}\n", e.Message);
            Console.WriteLine("Stack Trace:\n   {0}\n", e.StackTrace);
        }
    }

    private static void ShowOccurrences(String s, String toFind, int[] indexes)
    {
        Console.Write("'{0}' occurs at the following character positions: ",
                      toFind);
        for (int ctr = 0; ctr < indexes.Length; ctr++)
            Console.Write("{0}{1}", indexes[ctr],
                          ctr == indexes.Length - 1 ? "" : ", ");

        Console.WriteLine();
    }
}

A caller then calls FindOccurrences twice. In the second call to FindOccurrences, the caller passes a null as the search string, which cases the String.IndexOf(String, Int32) method to throw an ArgumentNullException exception. This exception is handled by the FindOccurrences method and passed back to the caller. Because the throw statement is used with no expression, the output from the example shows that the call stack is preserved.

References

1.     W3schools
3.     TutorialTeacher
4.     CsharpCorner



Comments

Popular posts from this blog

The String.Join Method in C# Explained

The String.Join Method in C#   The string.Join concatenates the elements of a specified array or the members of a collection, using the specified separator between each element or member. Overloads of string.Join Method Description Join(Char, Object[]) Concatenates the string representations of an array of objects, using the specified separator between each member. Join(Char, String[]) Concatenates an array of strings, using the specified separator between each member. Join(String, IEnumerable<String>) Concatenates the members of a constructed IEnumerable<T> collection of type String, using the specified separator between each member. Join(String, Object[]) Concatenates the elements of an object array, using the specified separator between each element. Join(String, String[]) Concatenates all the elements of a string array, usi...

Most Popular Programming Languages in 2020

Most Popular Programming Languages in 2020 In this blog post, you will learn about the most popular programming languages in 2020 for creating the best web applications. Check its pros and cons. Analyzed by technostacks Not very long ago, just a few people were considered to be computer programmers, and the general public viewed them with awe. In this digital age that we are now living in, however, a large number of IT jobs need a solid grasp of one or more programming languages. Whether one wants to develop a mobile app or get a certification for having programming knowledge, or even to learn new skills, one needs to opt for the right programming language. Below mentioned eight most popular programming languages which are in demand for software development and web applications. This is the most used programming languages in 2019 and will be in 2020. For each, there is little information about the language, benefits and its complexity, as well as about its usage. One must...

HashTable in C# with Example

  HashTable in C# with Example Hashtable  is used to store a collection of key/value pairs of different  data types  and are organized based on the hash code of the key.   Generally, the hashtable object will contain buckets to store elements of the collection. The bucket here, is a virtual subgroup of elements within the hashtable and each bucket is associated with a hash code, which is generated based on the key of an element.   In C#, hashtable is same as a  dictionary  object but the only difference is that the  dictionary  object is used to store a key-value pair of same  data type  elements.   When compared with  dictionary  object, the hashtable will provide a lower performance because the hashtable elements are of object type so the boxing and unboxing process will occur when we are storing or retrieving values from the hashtable.   C# HashTable Declaration Hashtable is a non-generic type...