#910 – One Example of a finally Block

You use a finally block when you have logic that should execute whether or not an exception occurs when executing a block of code.

One example of something that you might do in a finally block is to call a Dispose method on an object that implements IDisposable.  You would do this because you want to make sure that you always call Dispose on the disposable object, whether or not an exception occurs when using the object.

(Note: You can achieve the same pattern with the using statement, which automates invocation of a Dispose method).

            StreamWriter sw = new StreamWriter(@"D:\Log.txt");
            try
            {
                sw.Write(string.Format("Did something at {0}", DateTime.Now));
            }
            finally
            {
                sw.Dispose();
            }

#909 – When a finally Block Executes

The purpose of a finally block is to define some code that should always execute, whether or not an exception occurs while executing code in the corresponding try block.

Exactly when a finally block executes depends on several things:

  • If the code in the try block executes without throwing an exception or transferring control elsewhere
    • The finally block executes after the code in the try block
  • If an exception occurs while executing code in the try block ..
    • .. and the exception is caught in a catch block associated with the same try statement — the body of the catch block executes, followed by the body of the finally block
    • .. and the exception is not caught — the body of the finally block executes before the exception propagates back up the call stack
  • If a goto or return statement is encountered in the try block
    • The finally block executes before control is transferred

#908 – Handling Unhandled Exceptions

An unhandled exception is one that propagates up the call stack without being caught by an exception handler in a catch block.  By default, the .NET runtime will cause a dialog to be displayed when an unhandled exception occurs.

908-001

When an unhandled exception occurs, you can’t recover from the exception.  But you can do some final logging and then terminate the application quietly by adding a handler to the AppDomain.UnhandledException event.

        static void Main(string[] args)
        {
            // Specify handler for all unhandled exceptions
            AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;

            throw new ApplicationException("Something bad happened");

            Console.ReadLine();
        }

        static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            Exception theException = (Exception)e.ExceptionObject;

            Console.WriteLine("- In the unhandled exception handler -");
            Console.WriteLine(theException.ToString());

            // Exit to avoid unhandled exception dialog
            Environment.Exit(-1);
        }

908-002

#907 – Exceptions Thrown from Main Are Treated as Unhandled Exceptions

When an exception is thrown from a Main method and you don’t catch the exception within the Main method, the exception will be treated as an unhandled exception.  Because the Main method is the entry point, or topmost method, of your application, there is no higher level method where the exception can be handled.

When the unhandled exception occurs, the application will stop executing and display an error message.

In the example below, we throw an exception of type ApplicationException from the Main method, but do not catch the exception in Main.  The exception is dumped to the console output and we see an error dialog.

        static void Main(string[] args)
        {
            if (DateTime.Now.DayOfWeek == DayOfWeek.Monday)
                throw new ApplicationException("Sorry, I don't work on Mondays");

            Console.WriteLine("I'm running normally..");
        }

907-001

#906 – Adding Custom Data vs. Using a Custom Exception Type

There are two basic approaches to adding custom data to an exception that you’re going to throw.  In both cases, you can pass data back to the calling method that is unique to the specific problem that has occurred.

You can use either method, depending on the knowledge that your calling code has regarding either your custom exception type or the custom data that you add to the exception.  Creating a custom exception type gives you some more flexibility, because calling code can then add a handler that is specific to the new type.

#905 – Examining an Exception’s Stack Trace

When you access an exception object’s StackTrace property from within an exception handler, you only have access to a single multiline string that dumps out details about the stack.

For example:

905-001

This format is not ideal, since it’s fairly verbose and you have no ability to look at individual items within the stack.

If you want more control in formatting output that shows the stack, or you want to programmatically examine the stack, you can create a new System.Diagnostics.StackTrace object, passing it the Exception object that you’re handling.

Below is an example that dumps out a more abbreviated version of the stack and changes the order to match the calling sequence.

                catch (Exception ex)
                {
                    Console.WriteLine("** Caught exception, stack :");
                    StackTrace stack = new StackTrace(ex);
                    StackFrame[] frames = stack.GetFrames();
                    for (int i = frames.Count() - 1; i >= 0; i--)
                    {
                        MethodBase mb = frames[i].GetMethod();
                        Console.WriteLine("- {0}  [{1}]",
                            mb.Name,
                            mb.DeclaringType.FullName);
                    }
                }

905-002

#904 – Getting the Innermost Wrapped Exception

When you re-throw an exception, you can create a new exception that wraps the original exception by setting the InnerException property of the new exception to refer to the original exception.

An exception that wraps an inner exception can itself by wrapped.  When you catch an exception, the original cause of the exception might be several levels deep.  You can get to the original exception by looking at the InnerException property of each exception, working your way down until you find one that has a null value for InnerException.

You can also get access to the innermost exception using the Exception.GetBaseException method.  This method just follows the chain of exceptions using the InnerException and stops when it gets to the innermost exception.

                try
                {
                    DoDogStuff();
                }
                catch (ApplicationException wrappedEx)
                {
                    Console.WriteLine("** Main() caught ApplicationException:");
                    Console.WriteLine("  Base exception: ");
                    Console.WriteLine("  {0}", wrappedEx.GetBaseException().ToString());
                }

904-001

#903 – Wrapped Exceptions Can Be Several Levels Deep

When handling an exception, you can wrap the original exception in a new exception that you throw, by setting the InnerException property of the new exception to reference the original exception.

If it makes sense for your application, you can wrap an already-wrapped exception, such that the inner exception itself contains an inner exception.  You might also encounter wrapped exceptions that are several levels deep when using the .NET Framework.

In the example below, a Main method calls a DoDogStuff method.  DoDogStuff in turn calls Dog.Bark, which calls Dog.ReadBarkLog.  The original exception is wrapped, as follows:

  • ReadBarkLog throws an IOException
  • Dog.Bark catches the IOException and wraps it in a DogBarkException
  • DoDogStuff catches the DogBarkException and wraps it in an ApplicationException
  • Main catches the ApplicationException and then has access to both inner exceptions

903-001

 

#902 – Data Available to the Handler of a Wrapped Exception

There are cases when you handle an exception by wrapping the original exception within a new exception that you then throw.  The original exception is wrapped by storing it in the InnerException property of the new exception.

When a handler further up catches the new exception, it will see the following:

  • StackTrace property shows the calling sequence only down to the method that created the new exception (the handler that caught the lower-level exception)
  • The original (wrapped) exception is accessible through the InnerException property

For example, suppose that:

  • Main method calls DoDogStuff method, which calls Dog.Bark method
  • Dog.Bark throws a DogBarkException
  • DoDogStuff catches DogBarkException, wraps the exception in an ApplicationException and throws the new exception

A handler in Main can then catch the ApplicationException and will see:

  • StackTrace of wrapped exception shows – Main called DoDogStuff
  • InnerException contains the original DogBarkException
  • StackTrace of inner exception shows – DoDogStuff called Dog.Bark

902-001

902-002

#901 – Throwing a New Exception from a catch Block

Within a catch block, you can rethrow the original exception using the throw statement.  This allows any method further up in the call stack to also handle the exception.

There are also cases when you want to throw an exception that is different from the exception that you just caught.  You can do this using the throw new syntax and by storing the original exception in the new exception’s InnerException property.

In the example below, the code in the DoDogStuff method catches a DogBarkException, handles it, and then throws a new (more general) exception.

        static void Main(string[] args)
        {
            try
            {
                DoDogStuff();
            }
            catch (Exception xx)
            {
                Console.WriteLine("** Exception in Main():");
                Console.WriteLine(xx.ToString());
            }
        }

        static void DoDogStuff()
        {
            try
            {
                Dog d = new Dog("Kirby", 15);
                d.Bark(BarkSound.Woof, 99);
            }
            catch (DogBarkException xx)
            {
                Console.WriteLine(string.Format("** DogBarkException: Can't bark {0} times!", xx.NumTimes));
                throw new ApplicationException("Failure to do dog stuff", xx);
            }
        }

901-001