In the past ten plus years, my site partner Robbe Morris and I have personally read
and answered many thousands of forum posts on eggheadcafe.com. We welcome questions,
and we're also fortunate to have a cadre of expert repeat forum participants
who are here to help answer your questions. In fact, we think forum participation
is so important that instead of giving out recognition points and "badges"
we pay out real cash.
I particularly enjoy responding to questions because it keeps me sharp - it makes
me think and helps me to refine my writing technique to become ever more clear
and concise - a skill which I believe should not be lost on software developers
of any platform.
But over this period of time, one begins to see a pattern (or, should I say, an antipattern)
-- in these forum posts.
One of the patterns I see is the one where somebody makes a forum post and lists
an exception message with some sample code. Often when reading over their forum
post you can see immediately that during their development process, they had
no earthly idea where in their code this exception was thrown or why. They are,
in effect, "lost" in their own code! This leads me to my first recommendation:
Develop with exception wrappers. You can remove them later
During development, try to get in the habit of wrapping any code block that could
possibly throw an exception in a try / catch block. In the catch block, you can
set a breakpoint and examine the thrown exception via Intellisense in the Visual
Studio IDE. An example:
try
{
// your hot shot code here that you are sure is perfect!
}
catch (Exception ex)
{
// set a breakpoint on the next line!
System.Diagnostics.Debug.WriteLine (ex.ToString()); // this will show up in the Output window
}
That's so simple that it should become an afterthought -- you ought not to even
have to think about adding this bit of extra code. Why? Because if your code
causes a boo-boo, a breakpoint at the Debug.WriteLine statement will enable you
to mouse over and look at the exception's Message and StackTrace properties
in debug mode (as well as the InnerException property - very important, if there
is one) and instantly be able to tell exactly at what line in your code the exception
was thrown, and exactly what it was. So instead of mindlessly posting questions
on forums because you didn't take the time to do this, you instead have now
empowered yourself to become a better, more efficient developer! You'll not
only save time and frustration, but each time this happens you will begin to
learn more and more about the .NET Framework, it's idiosyncracies, and it's
behavior. I know this seems awfully basic, but you would be surprised at the
percentage of people who have never learned how to do it, or even - how to turn
on line numbers in the code window!
Unwind multiple expression statements into separate lines of code
Another slightly less common problem I see is that developers have a line of code
with multiple chained method calls or nested method calls in it. When an exception
is thrown, how can you tell which statement or expression is the culprit -- because
it is all on one line of code! During development, it's a good idea to get
into the habit of unwinding your statements, method calls or expressions, each
on a separate line. Then if an exception is thrown, it becomes much easier to
find out what happened and where.
Learn how to break on the exact point where an exception is thrown
Often when dealing with code that has more than one "level", an exception
may be thrown but it is not actually caught or handled until farther up the call
stack. This can make it very difficult to discern exactly where the exception
was thrown and makes accurate debugging very difficult. You can change this behavior
by telling the Visual Studio debugger to break at the exact line of code where
an exception is originally thrown:
At the top Visual Studio menubar, choose "Debug" and then "Exceptions".
Check the box that says "Thrown" under the Common Language Runtime
Exceptions.

You can also debug into third party assemblies for which you do not have source
code by going to Debug/ Options and unchecking the "Just My Code" box. Various DebuggerStepThrough and other attributes can be placed at key
blocks of code to control whether the debugger will step over or break on a particular
block of code.
Use Project References during the development process
Setting Project references to other projects in your Solution is preferable to setting
hard references to compiled assemblies. This allows the developer to "debug
through" - following the code path from one assembly to the next and being
able to examine values at various stages in the development process. It makes
it easier to find and fix errors in your code. If you have the source code, bring
the project into the solution and set your references to the project - not the
built assembly from the project.
Learn to program in a type-safe manner.
This is particularly important for developers who choose to use Visual Basic.NET.
Option Strict and Option Explicit should ALWAYS be turned on. This puts you at
least close to the league of the C# developer, who doesn't have to worry
about things like this because if they make a code mistake, their code simply
will not compile at all.
Unfortunately, VB.NET is much more forgiving (by design)- so if you want to be a
pro you'll need to bring it into line with other languages. Another thing
VB.NET developers need to understand is that not all languages are case-insensitive
(most are not). So if you're developing a class library that may be consumed
by a C# developer, you want to be extra careful not to set up ambiguities in
the casing of your properties and methods. Setting the CLSCompliant attribute
can help:
VB.NET:
<Assembly: CLSCompliant(True)>
<CLSCompliant(True)> Public Class MyCompliantClass
Public Sub ChangeValue(value As UInt32)
End Sub
Public Shared Sub Main()
Dim i As Integer = 2
Console.WriteLine(i)
End Sub
End Class
The above code generates the following Visual Basic compiler warning:
warning BC40028: Type of parameter 'value' is not CLS-compliant.
CLS compliant code must be exposed in the following if you use this attribute:
Definitions of your public classes.
Definitions of the public members of public classes, and of members accessible to
derived classes (family access).
Parameters and return types of public methods of public classes, and of methods accessible
to derived classes.
I hope these ideas are helpful to you as you go about your development adventures.