Exception Usage in .NET


Now that ExceptionMon is keeping an eye on your exceptions, I want to discuss using exceptions in .NET. The fact that .NET has exceptions built right in is certainly a cause for rejoicing. For those of us who came from C++ Win32 land, C++ exceptions were a great idea, but the implementation left a huge amount to be desired. Because .NET has a clean and consistent manner for handling exceptions from the .NET Framework class library (FCL) out, development will get quite a bit easier in .NET-land.

I was all set to write a complete chapter on exception handling, but my coworker Jeffrey Richter already did an outstanding job in his books Applied Microsoft .NET Framework Programming (Microsoft Press, 2002) and Applied Microsoft .NET Framework Programming in Microsoft Visual Basic .NET (Microsoft Press, 2003). His chapters on exception handling (Chapter 18, in both books) are mandatory reading for anyone doing .NET development. However, I do want to emphasize a few points on using and developing your own exceptions for your products.

The first key point is that exceptions are for exceptional events. We've all heard that phrase, but I've found that many developers have trouble actually defining it. My definition is that only when you encounter an error or unexpected condition do you throw the exception. One mistake I've seen developers make is using exceptions instead of a switch…case statement. (I really have!) The only time you throw is when something is wrong. Don't return general status codes by using exceptions.

One argument for always using exceptions is that developers never check return values. To me, that's a complete red herring argument, because if developers aren't checking return values, they aren't doing their jobs and should be fired. The reason I'm mentioning this is that I've seen people overusing exceptions when the code would be much cleaner and faster if they would simply return a value. The general rule I apply to my code is that I will always throw exceptions out of public methods and properties on error conditions. That way there's a consistent means of error handling for anyone using my code. Internally to my class, I will use return values instead of throwing on internal helper functions so that I can keep my exception throwing in the main methods. Of course, if one of those internal-only methods encounters a true error condition, I'll do the throw right there. It's all a matter of common sense.

I've mentioned the performance hit because even though exceptions seem to be free in .NET, they are implemented internally with standard structured exception handling (SEH). If you want to verify this, simply debug a .NET application using native mode–only debugging—you'll see all those first-chance exceptions being reported when you cause an exception. That means a happy trip to kernel mode on each exception. The idea, again, is to throw an exception on errors, not as part of normal program flow.

The biggest problem with using exceptions is that it's difficult to know what you should be catching when using the FCL. As Jeffrey points out in his chapter on exceptions (a rule you've probably had beaten into your head), catch only the exceptions germane to the objects you are using. Each method and property in the FCL documentation has a section named Exceptions. I always double-check the help when using each property or method (fortunately the F1 help has gotten smart enough to jump to the correct item) and check any exceptions thrown so that I can ensure I'm catching only what the documentation says is thrown. Keep your exception catching focused so that you don't accidentally chomp those you didn't expect.

Microsoft uses the same documentation comments in C# that you use to generate the MSDN help documentation, and as I pointed out in Chapter 9, you can generate nearly identical documentation with the excellent NDoc tool available from http://ndoc.sourceforge.net. To make life easier for anyone using your objects, you have to fill out the <exception></exception> tag and indicate any exceptions you throw in your code. It's also an excellent idea to double-check all FCL calls you make and to indicate which exceptions can be thrown from those methods so that you are giving the full report. When I'm doing code reviews, ensuring that exceptions are completely documented is one of my hot buttons and I always look to make sure they are.

Since I'm mentioning code reviews and exceptions, I'll point out three other things I always look for. The first is finally blocks in any methods or properties that are opening anything that could be construed as a handle-based resource, which ensures those items get cleaned up. I also look for any catch (Exception) {…} or catch {…} blocks and ensure they are doing a throw. Finally, I always double-check to make sure that re-throws never have a parameter after them like the following:

try {     // Do some stuff. } catch (DivideByZeroException e ) {     // DON'T DO THIS!!     throw e ; }

When you re-throw the exception, you lose the information about where the exception originated.

The final issue I want to mention about exceptions concerns the C# using statement. The using statement expands into the same Intermediate Language code as a try…finally block and calls the Dispose method on the single object specified inside the using statement. It's perfectly reasonable to use the using statement, but I prefer not to because what's happening behind the scenes isn't as obvious.




Debugging Applications for Microsoft. NET and Microsoft Windows
Debugging Applications for MicrosoftВ® .NET and Microsoft WindowsВ® (Pro-Developer)
ISBN: 0735615365
EAN: 2147483647
Year: 2003
Pages: 177
Authors: John Robbins

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net