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

Collections in C#

Collections in C# In our previous article , we have learned about how we can use arrays in C#. Arrays in programming are used to group a set of related objects. So one could create an array or a set of Integers, which could be accessed via one variable name. What is Collections in C#? Collections are similar to Arrays, it provides a more flexible way of working with a group of objects. In arrays, you would have noticed that you need to define the number of elements in an array beforehand. This had to be done when the array was declared. But in a collection, you don't need to define the size of the collection beforehand. You can add elements or even remove elements from the collection at any point of time. This article will focus on how we can work with the different collections available in C#. There are three distinct collection types in C#: standard generic concurrent The standard collections are found under the System.Collections. They do not store elemen...

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...

System.IO Namesapce in C#

  System.IO Namesapce in C# A  file  is a collection of data stored in a disk with a specific name and a directory path. When a file is opened for reading or writing, it becomes a  stream . The stream is basically the sequence of bytes passing through the communication path. There are two main streams: the  input stream  and the  output stream . The  input stream  is used for reading data from file (read operation) and the  output stream  is used for writing into the file (write operation). From the above definition of file, the C# provides a namespace that enable us to manipulate file in C# called System.IO.   System.IO  is a  namespace  and it contains a standard IO (input/output) types such as classes , structures , enumerations , and  delegates  to perform a read/write operations on different sources like file, memory, network, etc.   System.IO Classes The table below shows differen...