#856 – Choosing an Exception Type to Throw

When you throw an exception, you create and populate an instance of the System.Exception class, or one of its derived classes.

While it’s possible to throw an exception of type System.Exception, it’s not normally recommended.  You typically want to throw as specific an exception as possible, for two reasons:

  • To provide some specific details about what went wrong (e.g. filename that could not be found, rather than just a general message).
  • To allow an exception handler to catch specific types of exceptions

Typically, when throwing an exception, you do one of the following:

  • Throw an exception whose type matches one of the predefined exception types in the .NET Framework.  (E.g. System.ArgumentException)
  • Throw an instance of System.ApplicationException and provide a relevant message
  • Define your own custom exception type, which inherits from System.Exception, and throw an instance of that type.
Advertisement

#855 – Throwing an Exception

Your code can throw an exception to indicate that some sort of error occurred.  You’ll typically do this to indicate that something has gone wrong and the execution of the method cannot continue.

To throw an exception, you create an instance of the System.Exception class, or one of its derived classes, to contain information about what went wrong.  You use the throw statement to throw the exception.  Control returns immediately to the calling function and the exception “bubbles up” the call stack, looking for a calling method that can handle the exception.

Below, an exception is thrown if numTimesToBark is too large.

        public void Bark(int numTimesToBark)
        {
            if (numTimesToBark > 10)
            {
                string message =
                    string.Format("Dogs can bark at most 10 times.  {0} is too much barking",
                                  numTimesToBark);
                Exception exc = new Exception(message);
                throw exc;
            }

            for (int i = 0; i < numTimesToBark; i++)
                Console.WriteLine("Woof");
        }

#854 – Catching an Exception

You can catch an exception by using the combination of a try block and one or more catch clauses.  If any of the statements within the try block throws an exception and the exception type matches what is specified in the catch clause, the code within the catch clause will execute.

In the example below, we try reading from a file within a try block and we have a catch clause that handles exceptions of any type (System.Exception).  The using block disposes of the StreamReader object properly.

            static void Main(string[] args)
            {
                try
                {
                    using (StreamReader sr = new StreamReader(args[0]))
                    {
                        string firstLine = sr.ReadLine();
                        Console.WriteLine(firstLine);
                    }
                }
                catch (System.Exception exc)
                {
                    Console.WriteLine(exc.GetType());
                    Console.WriteLine(exc.Message);
                }
                Console.ReadLine();
            }
        }

If we run this code and pass in a non-existent file name, we see that we catch an exception of type FileNotFoundException.

854-001

#853 – An Exception Is an Instance of the System.Exception Class

When an exception is thrown, the method throwing the exception creates an instance of the System.Exception class and populates it with information about what went wrong.  This Exception object then travels up the call stack until a method that handles the exception is found.  This method “catches” the exception and can then query the Exception object to get information about the exception.

The exception must either be an instance of System.Exception or inherit (directly or indeirectly) from System.Exception.  A more specialized exception class is used when the method throwing the exception wants to include information in the exception object that is specific to the error that occurred.

For example, a method trying to read a file might throw a System.IO.FileNotFoundException.  This class inherits from System.IO.IOException, which inherits from System.SystemException, which in turn inherits from System.Exception.

For example:

853-001

#852 – How Exceptions Work

An exception is something that happens in your application at run-time that is unexpected and which requires special logic in order for the application to continue executing normally.

Here’s how exceptions work:

  • A particular piece of code calls a method, which in turn may call other methods
  • The call stack keeps track of the calling sequence that led to the currently executing method
  • At any given time, the code that is executing may decide to throw an exception, indicating that something unexpected happened
  • The method throwing an exception stops what it’s doing and control returns to the calling method
  • The calling method may decide to catch the exception, i.e. execute some code in response to it
  • If the calling method doesn’t catch the exception, control continues back up the stack until a method is found that does catch the exception
  • If no method catches the exception, it is unhandled

#851 – A General Philosophy for Handling Exceptions

An exception is an event that occurs at run-time and is not part of the normal expected execution of your code.  Exceptions can arise because of user errors, runtime errors, or bugs in your application.

You can include code in your application to catch and handle exceptions.  Your exception handling code will intercept exceptions that occur and you will then have a chance to react to the exception that is occurring.

As a general guideline for handling exceptions, you should:

  • Handle any exceptions that you can do something about.
    • E.g. Catch exceptions that indicate that the user entered malformed input and inform the user of what went wrong.
  • Include a top-level handler for unhandled exceptions
    • In this handler, inform the user that an unrecoverable error occurred.
    • Optionally, log information about the exception, to help diagnose what went wrong

#850 – Three Types of Errors that Can Lead to Exceptions

An exception is an event that occurs at run-time and is not part of the normal expected execution of your code.

There are different scenarios that can lead to an exception occurring while your application is executing.  They can be broken down into the following three categories:

  • User errors
  • Runtime errors
  • Bugs

user error is anything that the user does that you did not expect him to do.  For example, you might ask the user to enter his age and he enters “Bob” instead.

runtime error is an error that occurs as a result of something going wrong within one of the methods in the .NET Framework.  For example, you might run out of disk space while trying to write a file.

bug is a mistake that you make in your source code, which may lead to an exception.

#849 – Using the Call Stack in Visual Studio to Navigate within Your Code

When in break mode within Visual Studio, you can view the call stack in the Call Stack window.

When you bring up the Call Stack window, there will be a yellow arrow pointing to the top of the call stack, indicating the location of the next statement that will execute when you resume execution.  The Locals window will show the values of local variables within the current method.

849-001

At this point, you can double-click on another method within the call stack.  When you do, the code editor will show code for that other method and the Locals window will show local variables for the same method.  They will have the values that existed at the point that the method at the top of the call stack was called.  Notice that a yellow arrow still indicates the execution point, but a green arrow now appears, showing the current method being examined.

849-002

#848 – Viewing the Call Stack in Visual Studio

The call stack keeps track of the currently executing method in your application, and from where that method was called.  You can use the debugger in Visual Studio to view the current call stack when you are in break mode (at a breakpoint or stepping through your code).

If the call stack is not already visible, click on the Debug menu, then Windows and Call Stack.  (Or press Ctrl+D, C).

848-001

In the example below, we’ve started the application and are located in our Main method, which was called by native code.

848-002

If we now step into the Dog.BarkYourAge method, the call stack shows this method on the top of the stack, with Main as the second entry.  Main is just below BarkYourAge in the stack, because it called BarkYourAge.

848-003

If BarkYourAge then calls DogUtil.GenerateBark and we step into that method, we see:

848-004

If we return from GenerateBark, we see:

848-005

#847 – How the Call Stack Works

A call stack is an indication of which method in your application is currently executing and how the application got there.  When a method is called, information about that method is pushed onto the call stack.  When the method returns to its caller, that information is popped back off the stack.  In this way, the top of the stack always refers to the current method.  And, traversing down the stack, we see the sequence of calls that got us to the current method.

For example, assume that when your application starts, a Main method is called.  Information about Main is pushed onto the stack.

847-001

Assume that Main then creates an instance of a Dog object and calls its BarkYourAge method.

847-002

If BarkYourAge then calls method DogUtil.GenerateBark, we get:

847-003

When control returns from GenerateBark, we continue in the BarkYourAge method and the stack becomes:

847-002