Monday, January 14, 2013

Handling Exceptions in C#.NET


The first line of defense in an application is to check for potential error conditions before performing an operation. For example, a program can explicitly check whether the divisor is 0 before performing a calculation, or if a file exists before attempting to open it:

if (divisor != 0)
{
// It's safe to divide some number by divisor.
}
if (System.IO.File.Exists("myfile.txt"))
{
// You can now open the myfile.txt file.
// However, you should still use exception handling because a variety of
// problems can intervene (insufficient rights, hardware failure, etc.).
}

Even if you perform this basic level of “quality assurance,” your application is still vulnerable. For example, you have no way to protect against all the possible file access problems that occur, including hardware failures or network problems that could arise spontaneously in the middle of an operation. Similarly, you have no way to validate a user ID and password for a database before attempting to open a connection—and even if you did, that technique would be subject to its own set of potential errors. In some cases, it may not be practical to perform the full range of defensive checks, because they may impose a noticeable performance drag on your application. For all these reasons, you need a way to detect and deal with errors when they occur.

The solution is structured exception handling. To use structured exception handling, you wrap potentially problematic code in the special block structure shown here:

try
{
// Risky code goes here (i.e., opening a file, connecting to a database).
}
catch
{
// An error has been detected. You can deal with it here.
}
finally
{
// Time to clean up, regardless of whether or not there was an error.
}

The try statement enables error handling. Any exceptions that occur in the following lines can be “caught” automatically. The code in the catch block will be executed when an error is detected. And either way, whether a bug occurs or not, the finally section of the code will be executed last. This allows you to perform some basic cleanup, such as closing a database connection. 

The finally code is important because it will execute even if an error has occurred that will prevent the program from continuing. In other words, if an unrecoverable exception halts your application, you’ll still have the chance to release resources. The act of catching an exception neutralizes it. If all you want to do is render a specific error harmless, you don’t even need to add any code in the catch block of your error handler. Usually, however, this portion of the code will be used to report the error to the user or log it for future reference. In a separate component (such as a business object), this code might 
handle the exception, perform some cleanup, and then rethrow it to the calling code, which will be in the best position to remedy it or alert the user. Or it might actually create a new exception object with additional information and throw that.

No comments:
Write comments
Recommended Posts × +