Welcome Guest!
Create Account | Login
Locator+ Code:

Search:
FTPOnline
Channels Hot Topics Partner Sites Magazines About FTP RSS 2.0 Feed



email article
printer friendly
more resources

Handle Exceptions Gracefully
Exceptions happen. You need an intelligent approach to dealing with them.
by Bill Wagner

May 2003 Issue

Q. Write Exception-Safe Code
I'm developing a small project as a learning tool to become familiar with .NET. I have two questions on .NET error handling I'm hoping you can shed some light on. The rule I've followed in the past is that all routines in a VB project should have built-in error-handling code. I use On Error Resume Next when I set values in a textbox or label on a form, and when I set variables during form load or unload. I use On Error GoTo Handle_Err when calling another routine in a module or class. Overusing the Try ... Catch ... Finally structured exception-handling feature in VB.NET isn't recommended, because it incurs a performance penalty and could result in code that's difficult to maintain. How is overuse of VB.NET structured exception handling determined? What rule of thumb should I follow under VB.NET to ensure that my application doesn't throw unexpected (untrapped) errors and crash in a production environment—without incurring any performance penalities?
Carlton G. Henry, via e-mail

ADVERTISEMENT

A.
Although your question is VB.NET-specific, the answer is a general .NET development strategy. The answer has three parts: when to throw exceptions, how to make all your code robust in the face of exceptions, and where to catch exceptions.

When to throw exceptions is somewhat of a heuristic, but the simplest answer is to throw exceptions when you encounter error conditions you can't recover from. Try to avoid using exceptions to handle mundane error conditions. For example, I would expect users to place invalid entries in forms: chars where numbers are expected, phone numbers that don't parse correctly, and similar conditions. Don't use exceptions for these kinds of error conditions. You can handle the error locally in these cases, and the expected action is clear. I use exceptions when the code finding the error doesn't have the context to know what the system should do to correct or report the error condition, and the ramifications of an unchecked error are serious. For example, when I create a distributed system, I use exceptions to report that the server is unavailable. It's unclear how the system should handle this condition. Maybe it can use an offline cache, or maybe the program should exit. Clearly, the lower-level code that communicates with the server isn't in a position to make the corrections.

I follow two rules when I decide to throw an exception. First, the consequences of ignoring an error condition must be high. Null references, division by 0, and using disposed resources all cause the kinds of catastrophic failures that exceptions should handle, because they all make your application crash. Second, fixing the error locally must be impossible. To correct an error locally, you must be able to determine the correct alternate plan. If more than one reasonable alternative is possible, you must propagate the error and let client code determine the best course of action. The most effective way to propagate the error is to throw an exception.

Once you know you're throwing exceptions, it's time to work on the best strategy for handling them. You'll handle exceptions in most of your functions simply by propagating them. The C++ community developed a series of best practices for writing exception-safe code, explained in Herb Sutter's book, Exceptional C++ (see Resources). These practices adapt themselves easily to .NET development, and in fact I wrote about them a year ago (see Resources). If you can, implement the strong exception guarantee: No resources have leaked, any exceptions get propagated to the caller, and if the function exits by throwing an exception, the program state hasn't changed.

The last area to consider is when and how to catch exceptions. Remember that an uncaught exception terminates your program. This simple fact points to the first set of places to place catch clauses: All event handlers, Web service methods, and other interprocess entry points need catch clauses. At a minimum, these should report the error to the user and terminate the program. If more effective cleanup is possible, this is the place to do it.

In other cases, you should add catch clauses only if you can handle the exception completely. A bad design is often easier to spot than a good one. If your code contains catch clauses that rethrow the same or a different exception, this is indicative of a bad design. If you catch an exception, you should clean up completely. If a function can't clean up and fix a problem, you should propagate the exception and make sure that you implement one of the exception-safe guarantees.

The .NET Framework gives you all the tools to write effective and robust code that uses exceptions properly. If you follow the preceding guidelines, you'll throw exceptions only in truly exceptional cases, and the default handlers in the Main() routine or in your event handlers will keep your program from crashing.

About the Author
Bill Wagner is Windows technology expert. He is a contributing editor for and the author of , an advanced reference for C# developers. Bill has had a lead design role in many projects in his 16 years of software development. He has designed software for engineering and business applications, for desktop and Web environments. He has an extensive background in 2-D and 3-D graphics and multimedia software, including developing the video playback engine used for "The Lion King Animated Storybook." Reach him at . Back to top














Java Pro | Visual Studio Magazine | Windows Server System Magazine
.NET Magazine | Enterprise Architect | XML & Web Services Magazine
| | Discussions | Newsletters | FTP Home