#911 – finally Block Execution When Exception Is Rethrown

Recall that if an exception is caught in a catch block, an associated finally block will execute after the execution of the catch block.

If the catch block rethrows the exception, the finally block will execute after the catch block, but before the exception propagates back up the call stack.

In the example below, the sequence is:

  • Exception thrown from try block in HelperMethod
  • Exception caught in catch block in HelperMethodcatch block executes up to throw
  • finally block in HelperMethod executes
  • Exception caught in catch block of Main method
        static void Main(string[] args)
        {
            try
            {
                HelperMethod();
            }
            catch
            {
                Console.WriteLine("Caught exception in Main()");
            }

            Console.ReadLine();
        }

        static void HelperMethod()
        {
            try
            {
                throw new ApplicationException("Uh-oh");
            }
            catch
            {
                Console.WriteLine("In catch block, before re-throwing");
                throw;
            }
            finally
            {
                Console.WriteLine("In finally block");
            }
        }

911-001

#899 – Exception Type Variable in a catch Block Is Optional

In a catch block that specifies a particular exception type to catch, you’ll typically include a named variable representing the exception object that is caught.  Using this variable, code within your handler can access information about the exception that was caught.

            try
            {
                Dog d = new Dog("Kirby", 15);
                d.Bark(BarkSound.Woof, 99);
            }
            catch (DogBarkException dbe)
            {
                Console.WriteLine("Kirby didn't bark properly");
                Console.WriteLine(string.Format("Can't bark {0} times", dbe.NumTimes));
            }

If you don’t need to access data within the exception object, but you still want to catch exceptions of a specific type, you can omit the variable.  This will allow you to catch exceptions of a particular type, but not give you any access of data within the exception object.

            try
            {
                Dog d = new Dog("Kirby", 15);
                d.Bark(BarkSound.Woof, 99);
            }
            catch (DogBarkException)
            {
                Console.WriteLine("Kirby didn't bark properly");
            }

#889 – Catching Exceptions that Derive from a Common Base Type

When you specify an exception type to catch in a handler, the handler will catch all exceptions whose type matches the specified type.  It will also catch exceptions where the exception object’s type is a type that derives from the specified type.

In the example below, we catch exceptions of type System.ArgumentException.  This handler will catch exceptions where the exception object’s type is:

  • ArgumentException
  • ArgumentNullException  (derives from ArgumentException)
  • ArgumentOutOfRangeException  (derives from ArgumentException)
  • Any custom exception types you define that derive from ArgumentException or from one of its child classes
  • Various other exception types in the Framework that derive from ArgumentException
            try
            {
                Dog d = new Dog("Bob", 3);
                d.Bark();
            }
            catch (ArgumentException exc)
            {
                Console.WriteLine("You've got a problem with an argument");
                Console.WriteLine(exc.Message);
            }

#880 – Catching Different Exception Types at Different Levels

You can include catch blocks at different points in the call stack, to catch different types of exceptions.

In the example below, Main calls CreateSomeDogs, which in turn creates Dog instances and calls the Dog.Bark method.  CreateSomeDogs catches exceptions of type ArgumentException, but allows other exceptions to bubble back up to the Main method, where they are caught.

When we pass in a bad age for Kirby, the exception is caught in CreateSomeDogs and we continue with the for loop.  But when we ask Jack to bark, an exception is thrown that we then catch in Main.  This means that we exit CreateSomeDogs before we get a chance to create the Ruby Dog object.

        static void Main(string[] args)
        {
            try
            {
                string[] names = { "Kirby", "Jack", "Ruby" };
                int[] ages = { 150, 13, 1 };

                CreateSomeDogs(names, ages);
            }
            catch (Exception xx)
            {
                Console.WriteLine(xx.Message);
            }

            Console.ReadLine();
        }

        static void CreateSomeDogs(string[] names, int[] ages)
        {
            if (names.Count() != ages.Count())
                throw new Exception("# Names doesn't match # Ages");

            for (int i = 0; i < names.Count(); i++)
            {
                try
                {
                    Dog d = new Dog(names[i], ages[i]);
                    d.Bark();
                }
                catch (ArgumentException exc)
                {
                    Console.WriteLine(string.Format("Bad age {0} for dog {1}", ages[i], names[i]));
                }
            }
        }
        // Dog constructor
        public Dog(string name, int age)
        {
            if (age > 30)
                throw new ArgumentException("Age too big");

            Name = name;
            Age = age;
        }

        // Dog.Bark
        public void Bark()
        {
            if (Name.Equals("Jack"))
                throw new Exception("Jack can't bark");

            Console.WriteLine(string.Format("{0}: Woof", Name));
        }

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

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

#866 – A catch Block Without Arguments Catches All Exceptions

You typically include an argument in a catch block that indicates the type of exception to catch.

            catch (FileNotFoundException fnfExc)
            {
                Console.WriteLine(string.Format("Hey, we can't find file {0}!",
                                                fnfExc.FileName));
            }

You can also omit the arguments on the catch block entirely.  In this case, the catch block will catch all exceptions, regardless of their type.  Because you don’t declare an exception variable, however, you won’t have access to information about the exception.

            try
            {
                DoSomething();
            }
            catch
            {
                Console.WriteLine("No idea of what happened, but it must be something bad");
            }

Although possible, not specifying the type of exception to catch is not recommended.  Even exceptions originating from outside of CLS-compliant code will be wrapped in an exception whose type derives from Exception.  So you should always specify an exception variable in the catch clause.