Whether
you're writing code as a professional or a hobbyist, you want your code
to perform as advertised. For example, when a user clicks a button to
load information from a file, you want to make sure that file is there.
If the file isn't there, you need to have some way to deal with the
error.
In object-oriented programming (OOP), errors are often called exceptions.
An exception is just what it sounds like — anything that occurs in your
code that's exceptional or out of the ordinary. For example, if your
code opens a file and the file server goes down while you're accessing
the file, that's an exception. Comparatively, not being able to access
the file server or find a file in the first place isn't an exception
because your code can test to see whether the file exists before it
tries to open the file.
Code you write to address an exception is an exception handler. Exceptions that occur for which you haven't written code are unhandled exceptions, which can be fatal and cause your application to fail. Not good.
Visual Studio doesn't
provide exception-handling features. In many cases, you'll use the
built-in exception handlers supplied with the .NET Framework. In some
cases, you deal with exceptions by writing exception handlers in the
language of your choice. You can use Visual Studio to do the following:
Step through error-producing code in the Visual Studio Debugger.
Use Exception Assistant to view details about an exception.
Use code snippets to add exception handlers to your code.
The .NET Framework provides a model for managing exceptions that includes
Structured exception handling
A common-exception framework
The ability to create your own custom exceptions
1. Handling exceptions
In the good old days (say, more
than six years ago), it was every man for himself when it came to
handling exceptions. You could return a value when an exception
occurred or do nothing at all. Although plenty of ways are available
with which you can handle exceptions, you should
handle exceptions by using structured exception handling. Structured
exception handling makes it possible to handle exceptions in a
predictable manner. Structured exception handling also reduces the
learning curve for novice developers who must learn exception handling
techniques and makes your code easier to read. Consequently, everyone
wins when you use structured exception handling techniques.
Structured exception handling involves using the Try, Catch, and Finally statements to create code blocks:
Try: Executes statements that might cause an exception, such as opening database connections
Catch: Specifies the exception to catch and executes code to deal with the exception
Finally: Executes every time, whether exceptions generate or not
Another important feature of structured exception handling is the throw statement, which you use to create a new exception or to pass an existing exception to the calling function.
Here's an example of a Try...Catch...Finally block for opening and closing a database connection with ADO.NET:
Private Sub AccessData()
Dim MyConnection As New System.Data.SqlClient.SqlConnection
MyConnection.ConnectionString = My.Settings.MyDbString
Try
MyConnection.Open()
'send commands
Catch ex As Exception
'handle exception
Finally
MyConnection.Close()
End Try
End Sub
The statements executed in the Try block are wired to the Catch block. If any statement in the Try block throws an exception, the Catch block gives you a chance to
Any code in the optional Finally
block executes, regardless of whether an exception occurred. Place your
cleanup code, such as closing database connections, in the Finally block.
1.1. Catching exceptions
The .NET Framework provides an extensive catalog of exceptions that starts with the generic System.Exception. All exceptions inherit from System.Exception. You use a Catch block to capture exceptions and handle them. Table 1 lists examples of exceptions found in the .NET Framework.
Table 1. Example Exceptions Found in the .NET Framework
Exception | Usage |
---|
System.Exception | A generic exception |
System.NullReferenceException | Occurs when you attempt to access the value of an object that doesn't exist |
System.ArgumentNullReferenceException | Occurs when an unexpected nullreference is passed as an argument |
System.Data.SqlClient.SqlException | An exception thrown when SQL Server returns a warning or error |
System.IndexOutofRangeException | Thrown when you attempt to access beyond an array's index |
System.InvalidCastException | Thrown when an attempt to cast from one data type to another is invalid |
You can handle any of the exceptions listed in Table 1 by using a Catch block.
Catch blocks use the following syntax:
Here is a Catch block that catches an SQLException:
Catch ex As System.Data.SqlClient.SqlException
You can use multiple Catch
blocks to catch different kinds of exceptions. Depending on your
application, you may want to catch the most specific exception first.
The least specific exception is System.Exception.
For example, here are two Catch blocks:
Catch ex As System.Data.SqlClient.SqlException
'do something with the exception
Catch ex As System.Exception
'do something with the exception
Only one of these Catch blocks executes. Always list your Catch blocks in order of most specific to least specific. While your code executes, it starts at the first Catch block and steps through each until it finds a match. If System.Exception is the first Catch block, no other Catch blocks execute.
Figuring out which exceptions
you should use can be difficult. One option is to add the exception to
the Watch window while debugging. That allows you to see the specific
exception captured. Figure 1 shows an example of a System.Exception caught in the Watch window.
As Figure 1 shows, exceptions provide a lot of information. Some useful properties of exceptions include
Data: Gets a set of key/value pairs that provides optional, additional information about the exception
GetBaseException: Gets the root exception — the base exception — that causes a chain of exceptions to start
InnerException: Gets the exception that causes the current exception
The base exception's InnerException is null because the base exception is the first exception in the chain.
Message: Gets the exception's description
Source: Is used to get or set the name of the application or object that causes the exception
You can set the Source property before you pass an exception to another method to process.
|
|
StackTrace: Provides a list of all the methods called before the exception occurs
TargetSite: Gets the method that causes the exception
The method provided by the TargetSite is the same method listed at the top of the StackTrace.
NOTE
Always capture
information about exceptions. Exceptions don't always occur while
you're sitting in front of your laptop with a cup o' Joe and Debugger
fired up. Exceptions occur when you're two weeks past your deadline on
a new project and the last thing you have time for is something you
haven't thought about in six months to start malfunctioning. You can
use an exception's properties to puzzle out what caused the exception.
1.2. Throwing exceptions
When an exception occurs, the exception is thrown. The source of this term is the keyword throw, which is used to raise an exception when an error occurs.
Here are the two uses of the throw statement:
To raise an exception in your program: The syntax to throw an exception is throw someException.
For example, to throw an exception when a null value is passed to a method, use System.ArgumentNullException, as the following code demonstrates:
private string SayHello(string name)
{
if (name == null)
{
throw (new ArgumentNullException("name"));
}
else
{
return ("Hello " + name);
}
}
To pass an exception to a calling function: You use the throw statement within a Catch block to pass an existing exception to a calling function, as the following code shows:
try
{
/*Do something that causes an exception*/
}
catch (System.Exception ex)
{
}
The Catch block captures the exception, and the throw statement passes the captured exception to the calling function. Figure 2 shows an example of the throw statement in action.
Note the following in the code sample shown in Figure 2:
The subroutine Form1_Load() calls the function SayHello() on line 23.
On line 41, SayHello() throws an exception of the type System.ArgumentNullException because a null value was passed in as a parameter.
Code execution jumps to line 48, where the Catch block captures the exception.
Line 50 throws the exception to the caller, Form1_Load().
Execution returns to line 27, the Catch block in Form1_Load(), which captures the exception thrown to it by line 50.
Line 29 displays a message box that displays the exception's Message property, which is Value cannot be null.
Other times when you might want to use the throw statement include
To test your exception handlers:
You may find it helpful to have your unit test or other testing harness
throw exceptions to test your exception handlers and logging utilities.
When you use an exception-handling framework:
You should handle exceptions for many patterns. For example, in ASP.NET
Web sites, common exception handlers are typically placed in the Globals.aspx page. All your code's exception handlers simply use the throw statement. Any exceptions are automatically handled by an application-wide handler in Globals.aspx.
Using a centralized
exception handler makes it easier to ensure that all your exceptions
are logged properly. You can also make sure your users are sent to a
consistent error page.
|
|
2. Using Visual Studio to manage exceptions
The Microsoft .NET
Framework provides an extensive set of exceptions that you can catch
and throw. Although you can create your own exceptions, that isn't
necessary in most cases. Instead, use Object Browser to view the list
of exceptions available in the .NET Framework.
To use Object Browser, follow these steps:
Press Ctrl+Alt+J to open Object Browser.
From the Browse drop-down list, choose .NET Framework 4.
Type exception in the Search box and then press Enter.
A list of objects with the word exception in their names appears.
The .NET Framework uses a naming standard whereby all exceptions end with the word exception, such as System.FormatException.
Right-click one of the entries listed in Object Browser and choose Sort by Object Type from the shortcut menu that appears.
The objects are sorted by type. That way, you see all the exception objects grouped in the Classes folder.
By default, the list of objects is sorted alphabetically.
To view more information
about an exception, click the plus sign (+) to expand the exception.
Click an exception's name to view its properties and methods. A summary
pane lists summary information about the exception. Figure 3 shows the exceptions derived from the System.ArgumentException object.
To read more about an exception, click the exception in Object Browser and then press F1 to display help about the exception.
In most cases, you should use the most specific exception type available. For example, System.DivideByZeroException is more specific than System.ArithmeticException.
In most cases, you can tell which exception is more specific by looking
at the name. An arithmetic exception will include divide-by-zero
errors. You can also look at the Derived Types list, as shown in Figure 3. Exceptions that appear in this list are based on a more generic exception.
|
|
NOTE
All exceptions inherit from System.Exception. As a result, all exceptions have the same properties of System.Exception.
Visual Studio
provides Exception Assistant for viewing information about exceptions
while using Visual Studio Debugger. Visual Studio displays Exception
Assistant any time exceptions are either of the following conditions:
Unhandled: Any time Visual Studio encounters an exception while executing your code, Exception Assistant appears.
Caught:
While using the Visual Studio Debugger, you can open Exception
Assistant if the Debugger breaks at the point where the exception is
caught. Press Shift+Alt+F10 to open Exception Assistant.
Figure 4 shows an example of Exception Assistant for an unhandled exception. Exception Assistant provides you with
The exception's message
Tips for troubleshooting the exception message
The exception's properties
Click the View Detail link in the Actions portion of the Exception Assistant dialog box, as shown in Figure 4, to view the exception's properties.