I find myself throwing plain old System.Exception far too often. If only I had a complete reference of the many default Exception classes Microsoft provides, like the one Chris Sully provides in his article. That's good as a starting point, but I don't see things like System.Data.DataException in there. Does anyone know of a more comprehensive list of *Exception classes for all the common .NET namespaces?
While searching for this, I also found some interesting commentary on System.ApplicationException. I always wondered what the heck that was for, and a linked Microsoft page confirms my suspicions:
Designing exception hierarchies is tricky. Well-designed exception hierarchies are wide, not very deep, and contain only those exceptions for which there is a programmatic scenario for catching. We added ApplicationException thinking it would add value by grouping exceptions declared outside of the .NET Framework, but there is no scenario for catching ApplicationException and it only adds unnecessary depth to the hierarchy. You should not define new exception classes derived from ApplicationException; use Exception instead. In addition, you should not write code that catches ApplicationException.
Well, so much for that.
There's also some discussion about the merits of error codes vs. exceptions. Opinions vary, but the determining factor seems to be performance. The first entry in MSDN's Performance Tips and Tricks in .NET Applications talks about exceptions:
Throwing exceptions can be very expensive, so make sure that you don't throw a lot of them. Use Perfmon to see how many exceptions your application is throwing. It may surprise you to find that certain areas of your application throw more exceptions than you expected. For better granularity, you can also check the exception number programmatically by using Performance Counters.At some point in the development of your project, I suggest you turn on "Break on all exceptions" using the VS.NET Exceptions menu. This will expose any loops where you are catching thrown exceptions. That's how I found out we are using a a third party tree control which throws an exception on every row paint!Finding and designing away exception-heavy code can result in a decent perf win. Bear in mind that this has nothing to do with try/catch blocks: you only incur the cost when the actual exception is thrown. You can use as many try/catch blocks as you want. Using exceptions gratuitously is where you lose performance. For example, you should stay away from things like using exceptions for control flow.
That's a big deal, because throwing an exception is literally slower than making a database call. This really surprised me, because a DB query is incredibly slow. But it's true:
Yes, that's right - the decimal point is in the right place for function #2! The code path through the exception throwing route took almost 3 orders of magnitude longer than the raw code. This is why, for this article, I'm just not interested in minor optimisations of the source code since the impact of exceptions dwarfs them.
This sounds really bad, but in practice, it shouldn't matter. If you are using exceptions properly, they should rarely be occurring and therefore any performance cost is moot. Eric Gunnerson puts it best:
So, if you are not a programming God like those OS developers, you should consider using exceptions for your application errors. They are more powerful, more expressive, and less prone to abuse than error codes. They are one of the fundamental ways that we make managed programming more productive and less error prone. In fact, the CLR internally uses exceptions even in the unmanaged portions of the engine. However, there is a serious long term performance problem with exceptions and this must be factored into your decision.
Posted by Jeff Atwood View blog reactions
« We're Building the Space Shuttle Teaching Users to Read »
Interesting post, particularly this snippet:
"You should not define new exception classes derived from ApplicationException; use Exception instead. In addition, you should not write code that catches ApplicationException"
I spent some time trying to find out the best ways to do exception handling a few months ago, and found this article on MSDN:
entitled 'Best Practices for Handling Exceptions' which states:
"Do not derive user-defined exceptions from the Exception base class. For most applications, derive custom exceptions from the ApplicationException class."
I'm no power-coder, but these articles seem to contradict each other. This concerns me, especially as I have implemented the guidelines from the MSDN article in a lot of code already.
Any idea which one we should believe?
Andy on October 25, 2004 08:56 AMAndy,
There is conflicting advice on this issue. I have seen numerous credible sources say not to use Application Exception. I don't know why that MSDN article has not been updated to reflect that advice though. I currently derive from ApplicationException as that seems to be the "official" position of MS at this point in time.
Jeff,
I thought it was a bad practice to "throw Exception"? I thought if your error condition did not fit one of the built-in exception types you were supposed to always throw a custom exception? That's what I do anyway.
To All,
Writing proper exception handling is extremely difficult. Never underestimate the complexities involved. Every Java/.NET application I've taken over maintainence of has horrible exception handling that needs to be completely rewritten. That MSDN Best Practicies article Andy cited above is the best resource I've encountered thus far, but it is far from complete and an entire book could be written on this subject.
This will get worse before it gets better. Plenty of work for maintainance programmers going forward though.
Michael Maddox on October 25, 2004 09:54 AM"I thought it was a bad practice to "throw Exception"? I thought if your error condition did not fit one of the built-in exception types you were supposed to always throw a custom exception?"
Yes, that's what I am saying-- I want to map my Throw System.Exception to a more specific built in *Exception, whichever one is the closest map. There's no point in writing custom exception classes when an appropriate one already exists, after all. The problem is, I can't find one single point of reference for all *Exception classes!
I actually find the structured exception handling very intuitive (and VASTLY superior), once I worked past the initial "Hey, where's my crappy On Error Goto" mindset ;)
Jeff Atwood on October 25, 2004 12:49 PMOh, and also, I think System.ApplicationException is a bad idea. I've always thought that, so I am siding with the "don't use it, any other documentation is wrong" camp.
Jeff Atwood on October 25, 2004 12:51 PMIf a findSomething(key) method throws an exception if 'key' is not found, this may cause a performance problem. Not finding something
should not be an exceptional condition in this case.
Jeff, why don't you write something to reflect on the framework and compile a list of all the exceptions and post it?
sam on October 25, 2004 05:32 PMBecause I'm lazy?
Jeff Atwood on October 25, 2004 09:49 PMI hope this post is of some use:
http://www.dotnet247.com/247reference/msgs/4/24093.aspx
If you want to use wincv.exe, you can also find it here:
C:\Program Files\Microsoft Visual Studio .NET 2003\SDK\v1.1\Bin\wincv.exe
www.dotnet247.com is a very useful site, by the way.
Regards,
Andy.
"Because I'm lazy?"
I love this comment, Jeff.
It's the reason why programmers exist. People are lazy, and want somebody to help them do things automatically.
windchill:
"""If a findSomething(key) method throws an exception if 'key' is not found, this may cause a performance problem. Not finding something
should not be an exceptional condition in this case."""
if instead of throwing an exception, it returned VB Nothing when key wasn't found, wouldn't that be impossible to differentiate from the situation where key's value is intentionally VB Nothing?
this lookup should throw an error for this reason. if you don't want to encounter an error here you should only call the function if a call to findSomething.has_key(key) is successful.
onektwenty4 on June 29, 2007 02:29 PM| Content (c) 2008 Jeff Atwood. Logo image used with permission of the author. (c) 1993 Steven C. McConnell. All Rights Reserved. |