#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

Advertisements

#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