.NET Exception Hierarchy
In C#, the exception-handling mechanism allows only objects of class Exception (namespace System) and its derived classes to be thrown and caught. Note, however, that C# programs may interact with software components written in other .NET languages (such as C++) that do not restrict exception types. The general catch clause can be used to catch such exceptions.
This section overviews several of the .NET Framework's exception classes and focuses exclusively on exceptions that derived from class Exception. In addition, we discuss how to determine whether a particular method throws exceptions.
12.5.1. Classes ApplicationException and SystemException
Class Exception of namespace System is the base class of the .NET Framework exception class hierarchy. Two of the most important classes derived from Exception are ApplicationException and SystemException. ApplicationException is a base class that programmers can extend to create exception classes that are specific to their applications. We show how to create user-defined exception classes in Section 12.8. Programs can recover from most ApplicationExceptions and continue execution.
The CLR generates SystemExceptions, which can occur at any point during program execution. Many of these exceptions can be avoided if applications are coded properly. For example, if a program attempts to access an out-of-range array index, the CLR throws an exception of type IndexOutOfRangeException (a derived class of SystemException). Similarly, an exception occurs when a program uses an object reference to manipulate an object that does not yet exist (i.e., the reference has a value of null). Attempting to use a null reference causes a NullReferenceException (another derived class of SystemException). You saw earlier in this chapter that a DivideByZeroException occurs in integer division when a program attempts to divide by zero.
Other SystemException types thrown by the CLR include OutOfMemoryException, StackOverflowException and ExecutionEngineException. These are thrown when the something goes wrong that causes the CLR to become unstable. In some cases, such exceptions cannot even be caught. In general, it is best to simply log such exceptions then terminate your application.
A benefit of the exception class hierarchy is that a catch block can catch exceptions of a particular type orbecause of the is-a relationship of inheritancecan use a base-class type to catch exceptions in a hierarchy of related exception types. For example, Section 12.4.2 discussed the catch block with no parameter, which catches exceptions of all types (including those that are not derived from Exception). A catch block that specifies a parameter of type Exception can catch all exceptions that derive from Exception, because Exception is the base class of all exception classes. The advantage of this approach is that the exception handler can access the caught exception's information via the parameter in the catch. We demonstrated accessing the information in an exception in line 44 of Fig. 12.2. We'll say more about accessing exception information in Section 12.7.
Using inheritance with exceptions enables an catch block to catch related exceptions using a concise notation. A set of exception handlers could catch each derived-class exception type individually, but catching the base-class exception type is more concise. However, this technique makes sense only if the handling behavior is the same for a base class and all derived classes. Otherwise, catch each derived-class exception individually.
12.5.2. Determining Which Exceptions a Method Throws
How do we determine that an exception might occur in a program? For methods contained in the .NET Framework classes, read the detailed descriptions of the methods in the online documentation. If a method throws an exception its description contains a section called Exceptions that specifies the types of exceptions the method throws and briefly describes possible causes for the exceptions. For example, search for "Convert.ToInt32 method" in the Index of the Visual Studio online documentation (use the .NET Framework filter). Select the document entitled Convert.ToInt32 Method (System). In the document that describes the method, click the link Convert.ToInt32(String). In the document that appears, the Exceptions section (near the bottom of the document) indicates that method Convert.ToInt32 throws two exception typesFormatException and OverflowExceptionand describes the reason why each might occur.
|
It is more difficult to determine when the CLR throws exceptions. Such information appears in the C# Language Specification. This document defines C#'s syntax and specifies cases in which exceptions are thrown. Figure 12.2 demonstrated that the CLR throws a DivideByZeroException in integer arithmetic when a program attempts to divide by zero. Section 7.7.2 of the language specification (14.7.2 in the ECMA version) discusses the division operator and when DivideByZeroExceptions occur.