Exceptions and Exception Handling

The exception-handling features of C# will be familiar to the Java programmer; the exception-handling syntax is predominantly the same, although the languages differ significantly in their exception declaration requirements.

Declaring Exceptions

There is no requirement, and no ability, in C# for a function member to programmatically declare the exceptions it might throw. The only way to do so is in the API documentation. This has two consequences:

  • Java developers are accustomed to methods explicitly declaring the checked exceptions they might throw. The absence of a throws declaration means that the programmer is more reliant on API documentation than on the compiler.

  • Interface members cannot specify which exceptions the member implementations are expected to throw. A full and accurate implementation of an interface member can be achieved only by a disciplined developer referring to and accurately interpreting the interface documentation.

Catching Exceptions

The following example demonstrates the familiar try...catch...finally exception-handling syntax, along with new catch syntax introduced by C#:

try {
    // code that might throw an exception

} catch (ExceptionClass1 ex1) {        // catch clause 1
    // code to handle exceptions of class ExceptionClass1
    // with access to the thrown exception named ex1

} catch (ExceptionClass2) {        // catch clause 2
    // code to handle exceptions of class ExceptionClass2
    // but without access to the Exception instance

} catch {     // catch clause 3
    // code to handle any Exception, but without access
    // to the Exception instance

} finally {
    // code that executes no matter whether
    // the try block succeeds or fails
}

The example shows that

  • Catch clause 1 is exactly the same as the Java syntax.

  • Catch clause 2 allows the programmer to catch an exception without declaring a local variable; there is no access to the exception caught.

  • Catch clause 3, known as a general catch clause, is used to capture any previously unhandled exception regardless of type. Because all run-time exceptions inherit from System.Exception, it is simply a shorthand form of writing the following:

    try {
        // Some code
    } catch (System.Exception) {
        // Some exception-handling code
    }

Throwing Exceptions

Throwing exceptions is the same in C# as in Java. For example:

throw new ExceptionClass();

C# introduces a shorthand syntax for rethrowing caught exceptions: the throw statement with no parameters. This is required when using the new catch syntax described in the preceding section. For example:

try {
    // Some code
} catch {
    // Some exception handling code
    // Rethrow the caught exception
    throw;
}

Tip

The same performance issues with exceptions exist in C# as in Java. Throwing exceptions can be expensive and should not be used as a general flow control mechanism.

The Exception Hierarchy

The java.lang.Throwable class is the root of the Java exception class hierarchy. Two classes derive directly from Throwable: java.lang.Exception and java.lang.Error. Derived from Exception is a class named java.lang.RuntimeException. The Exception, Error, and RuntimeException subclasses of Throwable are central to the Java classification of exceptions into the checked and unchecked categories.

Unchecked exceptions are those derived from either the Error or RuntimeException class. The compiler makes no attempt to ensure that these exceptions are handled by the developer since they generally occur because of a run-time or program error that should be fixed.

Checked exceptions are those that the compiler ensures are caught and handled within the code or are declared in the throws clause of the method declaration. Checked exceptions include all exceptions derived from java.lang.Exception, excluding RuntimeException and its subclasses.

Because C# function members cannot declare exceptions, the compiler makes no attempt to ensure that exceptions are caught and handled correctly. All .NET exceptions can be considered to be unchecked exceptions in Java terminology.

.NET takes a simpler approach to classifying exceptions based on whether it is a system or an application-related exception. This is merely a convention and is not enforced by the compiler or the runtime.

The root of the exception hierarchy in .NET is System.Exception. System exceptions are represented by System.SystemException and application exceptions by System.ApplicationException, both of which are derived from System.Exception.

The System.Exception Class

Table 6-1 compares the functionality of .NET’s System.Exception class with that of the Java java.lang.Throwable class. Although not a part of either language specification, the use of exceptions is tightly integrated with both Java and C# and is appropriate to this chapter. Java and .NET both rely on the exception inheritance hierarchy as a classification mechanism to support the use of the catch clause.

Exception Chaining

Both .NET and Java version 1.4 support a standardized approach to exception chaining. This allows exceptions to be created and store a reference to another exception internally. The inner exception would usually be a reference to an exception that prompted the outer exception to be raised.

Table 6-1. Comparison of Java and C# Exception Members

Java

C#

Comments

Constructors

  

Throwable()

Exception()

Constructs a new exception instance.

Throwable(String)

Exception(string)

Constructs an exception with the specified message.

Throwable(String, Throwable)

Exception(string, Exception)

Constructs an exception with the specified message and chained exception.

Throwable(Throwable)

N/A

Not supported in .NET; use the previous constructor.

N/A

Exception(SerializationInfo, StreamingContext)

Constructs an exception from a previously serialized exception. See GetObjectData near the end of this table.

Member

  

fillInStackTrace()

N/A

Not supported. (Although Environment.StackTrace can be used if only a stack trace is needed.)

getCause()

InnerException

Gets the chained exception, or null if one has not been specified.

getLocalizedMessage()

N/A

.NET recommends that the message available through the Message property be localized. Java provides this second method, which should be overridden by deriving classes to return a localized version of the message.

getMessage()

Message

Gets a message that describes the exception.

getStackTrace()

StackTrace

Gets the stack trace from the exception as a string.

initCause()

N/A

Sets the chained exception reference. .NET allows this reference to be set only during construction.

printStackTrace()

N/A

Not supported. Use the ToString method followed by the appropriate Stream or Console method.

setStackTrace()

N/A

Not supported.

N/A

HelpLink

Gets or sets a link to related help information. Should be in the form of a URN or URL.

N/A

Source

Gets or sets the name of the application or object that caused the exception. By default, this will be the assembly name.

N/A

TargetSite

Gets a MethodBase class representing the method that threw the exception.

N/A

GetBaseException()

Returns the original exception at the root of the exception chain.

N/A

GetObjectData()

Serializes an exception.

N/A

HResult

Gets or sets a coded number that uniquely identifies an exception. Predominantly for legacy integration.

..................Content has been hidden....................

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