#876 – Unhandled Exceptions

If an exception is thrown while your code is executing and you don’t have a handler that catches the exception, it is considered an unhandled exception.  An unhandled exception is one that travels all the way back up the call stack without encountering a handler that catches the exception.

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

For example, if we call a method named MethodA from a console application and it throws an exception that we don’t catch, we see some information about the exception dumped to the console and an error window.

876-001

 

Here’s another example where a WPF application throws an exception when we click on a button and we don’t handle the exception:

876-002

Advertisement

#875 – Looking at the Call Stack after Catching an Exception

After an exception is thrown, it bubbles up the call stack until a handler that can handle the exception is found.  If you set a breakpoint in an exception handler, you can then use the debugger in Visual Studio to examine the call stack, as it existed at the time that the exception was thrown.

In the example below, we’ve hit a breakpoint that we set in an exception handler.  If we examine the Exception variable passed to the handler, we see that an exception of type ArgumentException has been thrown.

Notice that we can also look at the StackTrace property in the debugger.  It contains text describing the call stack at the time that the exception was thrown.  You can click on the magnifying glass icon to see the stack trace formatted in a way that’s easier to read.

In the example, we see that Dog.Bark threw the exception.

875-001

#874 – An Exception Can Be Thrown from a Constructor

You can throw an exception from a constructor.  For example, in the code below, the Dog constructor throws an exception if an invalid age parameter is passed in.

        // Dog constructor
        public Dog(string name, int age)
        {
            if ((age < 1) || (age > 29))
                throw new ArgumentException("Invalid dog age");

            Name = name;
            Age = age;
        }

The code below catches an exception that happens during construction. Note that the Dog object was never instantiated, so the reference is still null.

            Dog myNewDog = null;

            try
            {
                myNewDog = new Dog("Methuselah", 43);
                Console.WriteLine("We just created an old dog");
            }
            catch (Exception xx)
            {
                Console.WriteLine(
                    string.Format("Caught in Main(): {0}",
                                  xx.Message));
                bool nullDog = (myNewDog == null);
                Console.WriteLine(
                    string.Format("myNewDog is null = {0}", nullDog));
            }

874-001

#873 – Full Example of Throwing and Catching an Exception

Below is a complete example of throwing an exception from a method and catching/handling that exception further up the call stack.

Code for Dog class that throws an exception if we ask a dog to bark too many times:

    public class Dog
    {
        public string Name { get; set; }
        public int Age { get; set; }

        // Dog constructor
        public Dog(string name, int age)
        {
            Name = name;
            Age = age;
        }

        // Dog.Bark
        public void Bark(int numTimes)
        {
            if (numTimes > 10)
                throw new ArgumentException(
                    string.Format("{0} is just too many times to bark", numTimes));

            for (int i = 1; i <= numTimes; i++)
                Console.WriteLine("Woof");
        }
    }

Code that calls the Bark method, with an exception handler in the Main() method:

        static void Main(string[] args)
        {
            try
            {
                Console.WriteLine("Before MethodA call");
                MethodA();
                Console.WriteLine("After MethodA call");
            }
            catch (Exception xx)
            {
                Console.WriteLine(
                    string.Format("Caught in Main(): {0}",
                                  xx.Message));
            }

            Console.ReadLine();
        }

        private static void MethodA()
        {
            Console.WriteLine("Before MethodB call");
            MethodB();
            Console.WriteLine("After MethodB call");
        }

        private static void MethodB()
        {
            Dog d = new Dog("Kirby", 15);
            d.Bark(99);
            Console.WriteLine("I barked 99 times");
        }

Below is the output.
873-001

#872 – Code After a throw Statement Is Not Executed

When you throw an exception using the throw statement, control transfers immediately to the calling function.  No additional statements in the method containing the throw statement are executed.

In the example below, if you call the Bark method and pass in a value for numTimes that is greater than 10, an exception is thrown.  In this case, the for loop will never execute–i.e. the dog won’t bark.

        // Dog.Bark
        public void Bark(int numTimes)
        {
            if (numTimes > 10)
                throw new ArgumentException(
                    string.Format("{0} is just too many times to bark", numTimes));

            for (int i = 1; i <= numTimes; i++)
                Console.WriteLine("Woof");
        }

#871 – Where Execution Continues when an Exception Is Not Caught

When an exception is not caught by a try-catch statement, the code that follows the try-catch statement will not execute.

In the example below, Main() calls MethodA, which calls MethodB.  MethodB throws an exception, which is not caught by MethodA.  The exception bubbles back up to Main, where it is caught.  The code in MethodA that follows the try-catch statement is not executed.

        static void Main(string[] args)
        {
            try
            {
                MethodA();
            }
            catch (Exception xx)
            {
                Console.WriteLine("Caught exception in Main()");
            }

            Console.ReadLine();
        }

        private static void MethodA()
        {
            try
            {
                Console.WriteLine("Before MethodB call");
                MethodB();
                Console.WriteLine("After MethodB call");
            }
            catch (ArgumentOutOfRangeException argExc)
            {
                Console.WriteLine("MethodA catches ArgumentOutOfRangeException");
            }

            Console.WriteLine("In MethodA, after try-catch");
        }

        private static void MethodB()
        {
            throw new FileNotFoundException("Can't find your file");
            return;
        }

871-001

#870 – Where Execution Continues when an Exception Is Caught

When an exception is thrown that you catch in a catch block, the code in the catch block will execute.  Once all of the code in the catch block executes, execution will continue with the first line following the try-catch statement.  (Assuming that your catch block does not itself throw an exception).

            try
            {
                DoSomething();
                Console.WriteLine("In try block, before call that throws exception");
                DoSomethingThatThrowsAnException();
                Console.WriteLine("In try block, after call that throws exception");
                DoSomethingElse();
            }
            catch (FileNotFoundException noFileExc)
            {
                Console.WriteLine("FileNotFoundException");
            }
            catch (ArgumentOutOfRangeException argExc)
            {
                Console.WriteLine("ArgumentOutOfRangeException");
            }
            catch (Exception exc)
            {
                Console.WriteLine("Some other Exception");
            }

            Console.WriteLine("Now I'm continuing after the try-catch statement");

When this code runs, the statements in the try block begin executing.  The second method that we call results an exception, which is caught in the ArgumentOutOfRangeException catch block.  Once that block finishes executing, we continue with the code after the last catch block.

870-001

#869 – Example of Catching an Exception Thrown by the .NET Framework

Below is a complete example that shows how we might catch an exception thrown by the .NET Framework.

Our Dog class builds a list of all dogs created and allows you to retrieve a dog by index.

    public class Dog
    {
        private static List<Dog> _allDogs = new List<Dog>();

        public string Name { get; set; }
        public int Age { get; set; }

        // Standard constructor
        public Dog(string name, int age)
        {
            Name = name;
            Age = age;
            _allDogs.Add(this);
        }

        public static Dog DogByIndex(int index)
        {
            return _allDogs[index];
        }
    }

We can protect code that calls the DogByIndex method with a try-catch statement.

            try
            {
                Dog d1 = new Dog("Kirby", 15);
                Dog d2 = new Dog("Ruby", 3);

                // Later, get dog by index
                Dog someDog = Dog.DogByIndex(2);  // Oops--index of 2 is wrong!
            }
            catch (ArgumentOutOfRangeException exc)
            {
                Console.WriteLine("The dog index you used is out of range!");
                Console.WriteLine(exc.Message);
            }

869-001

#868 – List Most Specific Exception Types First

When you include more than one catch blocks as part of a try-catch statement, you must list the most specific exception types first.  When an exception occurs, the type of the exception object is compared with the type of each catch block in order, starting with the first.  When the type exception parameter in the catch block matches or is a parent type of the type of the exception, that catch block will “catch” the exception and later blocks will not be examined.

The compiler will enforce listing the most derived exception types first.  In the example below,  FileNotFoundException derives (indirectly) from Exception.  A handler for Exception cannot precede a handler for FileNotFoundException because the Exception handler will catch exceptions of both types.  The code below results in a compiler error.

                try
                {
                    DoSomething();
                }
                catch (Exception exc)
                {
                    Console.WriteLine("Exception");
                }
                catch (FileNotFoundException noFileExc)
                {
                    Console.WriteLine("FileNotFoundException");
                }

868-001

#867 – Including Several catch Blocks

You can include several catch blocks in a single try-catch statement, each catch block set up to catch a different kind of exception.

            try
            {
                DoSomething(5);
            }
            catch (FileNotFoundException noFileExc)
            {
                Console.WriteLine(string.Format("File Not Found: {0}", noFileExc.FileName));
            }
            catch (ArgumentOutOfRangeException argExc)
            {
                Console.WriteLine("Your arguments were not within valid ranges");
            }
            catch (Exception exc)
            {
                Console.WriteLine("Crap!");
                Console.WriteLine(exc.Message);
            }

If an exception originates within the the scope of the try block and if the exception is not caught at a lower level, it will bubble up to the code containing this try-catch statement.  The type of the exception object will then be compared to the exception types specified in the catch blocks, starting with the first block.  If a matching type is found, the code in that catch block will execute and the exception will not propagate further up the call stack.