C# Exception Handling

The C# language includes a mechanism for handling exceptions. An exception is an unexpected occurrence when a program is running. Examples of exceptions include:

If occurrences like these are not handled by the programmer, they are called unhandled exceptions and will result in a program ending abruptly, possibly with cryptic error messages. The programmer therefore needs to anticipate situations that might lead to trouble and provide code to handle them.

Several keywords are involved: try, throw, catch and finally.


Exception class

The Exception class is in the System namespace. It is Serializable (i.e, it could be written out to a data stream and reconstructed later). Among other things, it has four constructors:

     Exception(String Message)
     Exception() // default constructor
     Exception(String Message, System.Exception Inner);
     Exception(SerializationInfo, StreamingContext);

In the third of these, Inner is an earlier exception for which a catch block has thrown this one.

The fourth constructor is needed for serialization (and is less common).

It has methods including ToString() which creates and returns a string representation of the current exception (a lot of information). The ToString method is called implicitly if an Exception class instance is printed by Console.WriteLine().

It also has various properties such as Message (giving us the string argument of the constructor).

There are a number of standard classes derived from Exception:


General Structure

The general structure of exception handling looks something like this:

     try 
     {
      // code that might cause a problem
      // if (a problem is detected)
      // {
      //  create and throw a new instance of Exception (or of a class
      //  derived from Exception)
      // }
     }
     catch // optional
     {
      // code to handle the situation, such as printing an error message
     } 
     // There could be more than one catch block.  The first one that can handle
     // this exception is used and the rest are ignored.  Put them in order
     // from most to least specific.
     finally // optional
     {
      // code we want executed in any case even if there is no exception
     }

In general we have a try block and one or more catch blocks or a finally block, or both. (We might have try and finally without catch. Even if an error occurs in the try block, the finally block is still executed.)

If an error occurs that is inside a try block, there should be a corresponding catch block.

Is the finally block always executed? There are a few situations in which the process will be terminated at once. These include ExecutingEngineException, StackOverflowException and a few others. In most normal situations, the finally block will be executed.

Example (adapted from a MSDN page):

using System;

public class Example
{
 public static void Main()
 {
  int number1 = 3000;
  int number2 = 0;
  try 
  {
   Console.WriteLine(number1 / number2);
  }
  catch (DivideByZeroException) 
  {
   Console.WriteLine("Division of {0} by zero.", number1);
  }
 }
}
// The example displays the following output:
//        Division of 3000 by zero.

Notice that we are using try and catch but the throw is being done by the system.

End of Example

The example shows that you can catch errors such as "divide by 0" in which the exception is thrown by the system.

If an exception occurs that is inside a try block, the runtime environment starts looking for a suitable catch block, first in the current method and then in methods farther down the stack. After the code in the catch block, control passes to whatever follows that catch block in whatever method contains it. For instance:

When the XXXException occurs in JKL, C# looks for a catch block to handle it. As there is no catch block for XXXException in JKL, it looks in GHI, doesn't find one, looks in DEF, doesn't find one, and then looks in ABC, where it finds a suitable catch block.

Notice that the exception is being handled quite far from where it occurred. This could be inconvenient. Try to catch an exception as soon as you can.

If there no catch block for an exception, you should expect that your program will abruptly halt at that point.

A catch block specifies what kind of exception it expects to handle. We could have several catch blocks for different kinds of exceptions (which might be generated by the same code), folowed by one that would catch a generic Exception (the base class) (which should be listed last).


Invent your own exception

It is not usually a good idea, but it is possible to derive your own specialized exception class from System.Exception. It might look like this: (Adapted from a MSDN page)

     [Serializable()]
     public class MyException : System.Exception
     {
      public MyException() : base() { }
      public MyException(String Message) : base(Message) { }
      public MyException(String Message, System.Exception Inner) : base(Message, Inner) { }

      // This last constructor is needed for serialization when an exception
      // propagates from a remoting server to the client. 
      protected MyException(System.Runtime.Serialization.SerializationInfo info,
          System.Runtime.Serialization.StreamingContext context) { }
     }

     private static void TestThrow()
     {
      MyException ex = new MyException("Custom exception in TestThrow()");
      throw ex;
     }

     static void TestCatch()
     {
      try
      {
       TestThrow();
      }
      catch (MyException ex)
      {
       System.Console.WriteLine(ex.ToString());
      }
     }

It is possible to add properties to a custom exception class, but it is seldom necessary and would require rewriting ToString().


"Using" as a convenience

If we are dealing with some kind of resource, such as working with a file, we want to be sure that no matter what happens, the resource will be freed afterward. We might have code like this:

     try
     {
      StreamWriter SW = new StreamWriter("TestFile.txt");
      SW.WriteLine("This is an example."); 
     }
     finally
     {
      SW.Close();   
     }

This could instead be done with "using":

     using (StreamWriter SW = new StreamWriter("TestFile.txt"))
     {
      SW.WriteLine("This is an example.");
     }

which takes the place of the try and finally blocks.

The "using" construct is a shortcut for "try" and "finally" here.


Examples

These are adapted from MSDN pages.

In the first example, notice that it is the system which will detect the fact that index is out of range. There is no need here to test for it and throw an exception. Notice that the catch block throws an exception of its own.

     static int GetValueFromArray(int[] array, int index)
     {
      try
      {
       return array[index];
      }
      catch (System.IndexOutOfRangeException ex)
      {
       System.ArgumentException argEx = new System.ArgumentException("Index is out of range", "index", ex);
       throw argEx;
      }
     }

In the second example, we try to write to a file. If this fails, we want to be sure the file is closed, so we use a finally block. It is possible the file was never opened, in which case attempting to close would be an error (causing an exception), so we check for file != null.

     static void CodeWithCleanup()
     {
      System.IO.FileStream file = null;
      System.IO.FileInfo fileInfo = null;
      try
      {
       fileInfo = new System.IO.FileInfo("C:\\file.txt");
       file = fileInfo.OpenWrite();
       file.WriteByte(0xF);
      }
      catch(System.UnauthorizedAccessException e)
      {
       System.Console.WriteLine(e.Message);
      }
      finally
      {
       if (file != null)
       {
        file.Close();
       }
      }
     }


Programming Advice

Never try to catch an exception unless you know how to handle it.

A catch block may partially handle an exception and then pass it on to other catch blocks (e.g., it might first make a note in a log file and then pass the exception on).

If you catch an exception of System.Exception (the base class), always rethrow it at the end of the catch block (to something more specific).

When should you throw an exception?

List catch blocks with the most specific exception types first.

The only action to take with an exception is to throw it or catch it. Do not use it as a parameter or as a return value.

Exceptions should be used only to handle error conditions. Do not invent alternate uses for them. This is not the same idea as an event and an event handler: events are normal and healthy but an exception means something has gone wrong.