#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