Chapter 16: Throwing and Catching Exceptions

Quiz Solutions

Solution to Question 16-1. An exception is an object (derived from System.Exception) that contains information about a problematic event. The framework supports throwing exceptions to stop processing and catching events to handle the problem and resume processing.

Solution to Question 16-2. The difference between a bug and an exception is that a bug is an error in programming, one that should be caught either by the compiler or in testing before you turn the program over to users. An exception is code that accounts for a situation that can’t be avoided during coding, but can be predicted, such as a lost database connection.

Solution to Question 16-3. To generate an exception, you use the throw keyword, although the system will generate some exceptions on its own.

Solution to Question 16-4. To handle an exception, you wrap the code you think might generate the exception in a try block. The code to handle the exception goes in an associated catch block.

Solution to Question 16-5. If no exception handler is found in the method that throws an event, the stack is unwound until a handler is found, or else the exception is handled by the CLR, which terminates the program.

Solution to Question 16-6. After the handler’s code is run, the program execution resumes with the code immediately following the handler (that is, after the catch block). Depending on where the handler is located in your code, and where the exception is thrown, you may be unable to return to the method where the exception was generated.

Solution to Question 16-7. The syntax for throwing a new ArgumentNull exception is:

throw new Sytem.ArgumentNullException( );

Solution to Question 16-8. You can write multiple exception handlers to handle different types of exceptions; the first handler that catches the thrown exception will prevent further handling. Beware of inheritance complications in the ordering of your handlers.

Solution to Question 16-9. If you have code that must run whether or not an exception is thrown (to close a file, for example), place that code in the finally block. You must have a try before the finally, but a catch is optional.

Solution to Question 16-10. You often won’t need a custom exception class; C# provides many exception types for your needs. However, you may want to create a custom exception to define a situation that’s unique to the design of your program, and would not be an error outside it.

Exercise Solutions

Solution to Exercise 16-1. Create a simple array of three integers. Ask the user which array element she wants to see. Output the integer that the user asked for (remember that the user probably won’t ask for a zero-based index). Provide a way for the user to indicate whether she wants another integer, or to end the program. Provide a handler that deals with invalid input.

This is a simple exercise, but the point is to create the error handler. Setting up the array is easy, as is asking the user for input. If you’re keeping the user’s requested index in a variable called theEntry, for example, remember to return theIntArray[theEntry - 1] to account for the fact that the user probably won’t be thinking in terms of zero-based indexes.

To allow the user to keep asking for integers until she gets bored, wrap the whole thing in a while loop with a simple Boolean for a control variable. Initialize the Boolean to true before you start the loop. Then, inside the loop, ask the user whether she wants to try again, and use another ReadLine( ) to get the response. If the response is "Y" (or "y" for safety), you leave the Boolean set to true and go around the loop again. If it’s anything else, change the Boolean to false and terminate the program.

None of that is the interesting part, though. Enclose the input line and the output for the selected index in a try block. Immediately after the try block, insert a generic catch block to output a message that the error is invalid. This catch block will handle whatever exception is raised, regardless of what kind of exception it is. The user can enter a number that’s out of range, a string, or anything else. Then execution continues with the test for the loop, allowing the user to try again if she gave bad input. Example A-46 shows one solution.

Example A-46. One solution to Exercise 16-1

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Exercise_16_1
{
    class Tester
    {
        public void Run( )
        {
            bool tryAgain = true;
            while (tryAgain)
            {
                int[] theIntArray = new int[] { 15, 27, 34 };
                Console.Write("Which array member would you like? ");

                try
                {
                    int theEntry = Convert.ToInt32(Console.ReadLine( ));
                    Console.WriteLine("The entry you asked for is {0}",
                                        theIntArray[theEntry - 1]);
                }

                catch
                {
                    Console.WriteLine("That isn't a valid entry.");
                }

                Console.Write("Try again (y/n)? ");
                string theReply = Console.ReadLine( );
                tryAgain = (theReply == "y" || theReply == "Y");
            }
        }

        static void Main(string[] args)
        {
            Tester t = new Tester( );
            t.Run( );
        }
    }
}

Solution to Exercise 16-2. Modify the example in Exercise 16-1 to handle two specific errors: the IndexOutOfRangeException, which is used when the user enters a number that’s not valid for the array, and the FormatException, which is used when the entered value doesn’t match the expected format—in this case, if the user enters something that isn’t a number. Leave the existing handler as a default.

You already have most of the program to start with. In this case you simply need to add two exception handlers with appropriate code. It doesn’t matter whether you catch the IndexOutOfRangeException or the FormatException first, but you must make sure that both handlers appear before the generic catch block, or the generic block will catch all the exceptions. Example A-47 shows one way to do it.

Example A-47. One solution to Exercise 16-2

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Exercise_16_2
{
    class Tester
    {
        public void Run( )
        {
            bool tryAgain = true;
            while (tryAgain)
            {
                int[] theIntArray = new int[] { 15, 27, 34 };
                Console.Write("Which array member would you like? ");

                try
                {
                    int theEntry = Convert.ToInt32(Console.ReadLine( ));
                    Console.WriteLine("The entry you asked for is {0}",
                                       theIntArray[theEntry - 1]);
                }

                catch (IndexOutOfRangeException)
                {
                    Console.WriteLine("Please enter a number from 1 to
                                      {0}.", theIntArray.Length);
                }

                catch (FormatException)
                {
                    Console.WriteLine("Please enter a number.");
                }
                catch
                {
                    Console.WriteLine("That isn't a valid entry.");
                }

                Console.Write("Try again (y/n)? ");
                string theReply = Console.ReadLine( );
                tryAgain = (theReply == "y" || theReply == "Y");
            }
        }

        static void Main(string[] args)
        {
            Tester t = new Tester( );
            t.Run( );
        }
    }
}

Solution to Exercise 16-3. Create a Cat class with one int property: Age. Write a program that creates a List of Cat objects in a try block. Create multiple catch statements to handle an ArgumentOutOfRangeException and an unknown exception, and a finally block to simulate deallocating the Cat objects. Write test code to throw an exception that you will catch and handle.

Refer back to Chapter 14 if you don’t remember how to create a generic List<T>, in this case a List<Cat>. This exercise isn’t too different from the last one, in that you’re still trying to allocate an invalid index inside the try block, and creating a catch block to handle two different types of exceptions. The difference in this case is the inclusion of a finally block, to take care of cleaning up the mystery resource you allocated. Example A-48 shows how we did it.

Example A-48. Our solution to Exercise 16-3

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Exercise_16_3
{
    class Cat
    {
        public int Age { get; set; }
        public Cat(int age)
        {
            this.Age = age;
        }
    }
    class Tester
    {
        private void CatManager(Cat kitty)
        {
            Console.WriteLine("Managing a cat who is " + kitty.Age +
                              " years old");
        }
        public void Run( )
        {
            try
            {
                Console.WriteLine("Allocate resource that must
                                   be deallocated here");
                List<Cat> cats = new List<Cat>( );
                cats.Add(new Cat(5));
                cats.Add(new Cat(7));
                CatManager(cats[1]); // pass in the second cat
                CatManager(cats[2]); // pass in the nonexistent third cat
            }

            catch (System.ArgumentOutOfRangeException)
            {
                Console.WriteLine("We're sorry; your cat does not exist.");
            }
            catch (Exception e)
            {
                Console.WriteLine("Unknown exception caught" + e.Message);
            }
            finally
            {
                Console.WriteLine("Deallocation of resource here.");
            }
        }
        static void Main( )
        {
            Console.WriteLine("Enter Main...");
            Tester t = new Tester( );
            t.Run( );
            Console.WriteLine("Exit Main...");
        }
    }
}

The output from this example would look like this:

Enter Main...
Allocate resource that must be deallocated here
Managing a cat who is 7 years old
We're sorry; your cat does not exist.
Deallocation of resource here.
Exit Main...

Your output may vary, depending on how you wrote your test code.

Solution to Exercise 16-4. Modify the test code you wrote in Exercise 16-3 so that it does not throw an error. Create a custom error type CustomCatError that derives from System.ApplicationException, and create a handler for it. Add a method to CatManager that checks the cat’s age and throws a new error of type CustomCatError if the age is less than or equal to 0, with an appropriate message. Write some test code to test your new exception.

This exercise is similar to Exercise 16-3, but this time you’ll need to create a custom error class. Fortunately, the custom error class is empty and simply passes the exception message to its base class, so that’s not too hard. Because the system can’t throw your custom exception automatically, you’ll need to add a TestCat( ) method to test the cat’s age and, if appropriate, throw a new CustomCatError object with an appropriate message. Our solution is in Example A-49.

Example A-49. Our solution to Exercise 16-4

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Exercise_16_4
{
    class Cat
    {
        public int Age { get; set;}
        public Cat(int age)
        {
            this.Age = age;
        }
    }

    // custom exception class
    public class CustomCatException : System.ApplicationException
    {
        public CustomCatException(string message) : base(message)
           // pass the message up to the base class
        {
        }
    }

    class Tester
    {
        private void CheckCat(Cat testCat)
        {
            if (testCat.Age <= 0)
            {
                // create a custom exception instance
                CustomCatException e = new CustomCatException("Your cat
                                       is too young.");
                e.HelpLink = "http://www.libertyassociates.com";
                throw e;
            }
        }
        private void CatManager(Cat kitty)
        {
            CheckCat(kitty);
            Console.WriteLine("Managing a cat who is " + kitty.Age + " years old");
        }
        public void Run( )
        {
            try
            {
                Console.WriteLine("Allocate resource that must
                                  be deallocated here");
                List<Cat> cats = new List<Cat>( );
                cats.Add(new Cat(7));
                cats.Add(new Cat(-2));
                CatManager(cats[0]); // pass in the first cat
                CatManager(cats[1]); // pass in the second cat
            }
            // catch custom exception
            catch (CustomCatException e)
            {
                Console.WriteLine("
CustomCatException! Msg: {0}", e.Message);
                Console.WriteLine("
HelpLink: {0}
", e.HelpLink);
            }
            catch (System.ArgumentOutOfRangeException)
            {
                Console.WriteLine("We're sorry; your cat does not exist.");
            }
            catch (Exception e)
            {
                Console.WriteLine("Unknown exception caught" + e.Message);
            }
            finally
            {
                Console.WriteLine("Deallocation of resource here.");
            }
        }
        static void Main( )
        {
            Console.WriteLine("Enter Main...");
            Tester t = new Tester( );
            t.Run( );
            Console.WriteLine("Exit Main...");
        }
    }
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset