With many bugs (most, one would hope), a debugger is your best friend.  You step through the code, make sure it’s doing what it’s supposed to, have it break on exceptions (just thrown or unhandled), skip around the code, check for variables at various places in the stack, inspect data structures, etc. etc. etc.

On occasion, you run across timing / race condition / threading bugs – bugs where breaking the execution isn’t acceptable, as it masks the bug, or causes other problems (timeouts, for instance).  In many of those instances, what developers tend to do is insert the good old standby printf’s ({Console,Debug,Trace}.WriteLine, whatever) – you don’t actually use the debugger for debugging any more, you use a bunch of text output that lets you know what happened when.

Unfortunately, this approach is both tedious (you have to go add those printf’s to debug, then take them back out later) and time-consuming (if you decide you want to printf a different value, or additional information, you need to edit the source, build, etc.)

An excellent feature in Whidbey is basically breakpoints that don’t actually stop execution – they’re called tracepoints. 

While the menu makes them look like different entities, they’re not really, you can convert either to the other easily enough – a tracepoint just defaults to printing a message and continuing execution, and a breakpoint is vice-versa.  If you have an existing breakpoint and decide “Hey, I don’t want it to actually stop here, but I would like to see the stack”, you can right-click on the breakpoint to bring up the When Hit entry in the context menu.

Then, you want to toggle the “Print a message” checkbox, which defaults to the Continue Execution checkbox also being turned on.

You can see in the dialog box that comes up the built-in values that are available, as is all other instance, local, etc. variables.

On many timing bugs, I enter tracepoints to dump the $CALLSTACK so I can see where the extraneous calls to a certain method are coming from.