Managing an Overload of First Chance Exceptions
You might find, while working your way through the code, that you encounter the exact same first chance exception over and over, making it impossible for you to look for others. If this is the case you can instruct the debugger to ignore that particular exception. This is generally ill-advised; it's far better to resolve the bug rather than suppress it, but that isn't always possible.
To suppress the bug, you need to put some more fine-grained control in the debugger. Thus far, I've only showed you first chance exception handling at a very gross level. But by expanding the nodes in the Debug Exceptions dialog you can identify the specific exception that keeps getting thrown and reset it so that it will no longer break into the debugger when it occurs. This can help you remain productive in your task of identifying avoidable exceptions in the application, even if there are many of them.
Protecting Against Exceptions
In most cases it's easy to protect against exceptions. You test for a null value before trying to access a property of the objector you check to make sure a file exists before reading it. These checks are simple and relatively efficient if done correctly. They are certainly less costly than allowing an exception to be thrown and then dealing with the exception.
There are only a few exceptions that are unavoidable or where checking for the condition is unfeasible. For instance, it's technically possible to determine before a call whether Windows will have to throw an Out of Memory exception. However, the frequency of this exception is very, very low and the cost in terms of code to check for this situation is fairly high. So in some cases, like this one, it is not cost-effective to write explicit tests for all of the things that might cause an exception.
Restructuring to Avoid Exceptions
Sometimes it's not an issue of testing for the thing that may cause the exception; it's a matter of restructuring the code in a way that the chances of an exception are minimized. In the above example, it would be better to use a for statement that limits the size of the array indexer to the actual size of the array. This automatically terminates the loop when the end of the array is encountered.
Restructuring a trivial example like the one given above is, well, trivial. However, restructuring larger sections of code may be more difficult. A few tips that may help you restructure your application code to avoid exceptions are:
- Review the call stack when the error is occurring. The call stack can show you at a glance how the execution got down into a particular method and can allow you to quickly see the structure of the existing code that may need to change.
- Identify the root cause. While the actual exception may be the result of a missing file, the root cause may be the failure of a previous process or bad input from the user. Identify the root cause and put error handling and exception avoidance code there.
- Add breakpoints. Breakpoints can help you see where things first went awry or illuminate subtle nuances of the code execution, such as the state of other variables, which may not be available once the exception occurs.
While hidden exceptions are a huge performance drain it doesn't mean that they have to suck the life out of your application. By knowing how to identify them and using the tools you already have you can quickly remove them and regain performance your application has lost.