The first tips for optimizing the Visual Studio debugger
utilize Attributes. Attributes are a fantastic way to add additional semantic
information about your code in a declarative fashion, and in this case they are
used to inform the debugger that certain code sections should be treated
differently. You can learn more about attributes with Programming with Attributes.
DebuggerStepThrough (1.x/2.x)
The System.Diagnostics.DebuggerStepThrough attribute (docs)
informs the Visual Studio debugger (or, technically, any debugger) that the
decorated method should not be stepped into, even when the Step Into command is
given. It does, however, still allow for (and honor) breakpoints to be set
within the method.
By adding the DebuggerStepThrough attribute to property
declarations, a lot of unnecessary steps can be taken out of the debugging
process, since property accessors would then be treated as simple fields.
Unfortunately, you cannot simply apply this attribute to a property, it must be
set for each accessor. As such, the Name property could be rewritten as
follows:
Listing 3
private string _name;
public string Name
{
[DebuggerStepThrough]get
{
return _name;
}
[DebuggerStepThrough]set
{
_name = value;
}
}
After making these changes and stepping through the code
from Listing 1, the total number of F11 (step into) actions required to step
through the code is reduced to 5 -- one per line of code. This represents a
reduction of 54%!
DebuggerBrowsable (2.x)
The next attribute that can improve the debugging experience
is System.Diagnostics.DebuggerBrowsable (docs).
This attribute works with the Locals window, and can be used to eliminate
redundant fields. This attribute accepts one parameter which must be one of
the DebuggerBrowsableState enumeration values of Never, Collapsed, or
RootHidden. Collapsed is the default behavior you are probably familiar with.
None can be used to hide certain fields from being displayed. The RootHidden
option will hide the root object, but will show its children if the member is
an array or collection. Unfortunately, this attribute is not supported by
Visual Basic.
Using this attribute in our example, we can mask the
presence of the private local _name variable from the Locals window. Listing 4
shows our updated property code, while Figure 2 shows the resulting Locals
window.
Listing 4
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private string _name;
public string Name
{
[DebuggerStepThrough]get
{
return _name;
}
[DebuggerStepThrough]set
{
_name = value;
}
}
Figure 2
DebuggerDisplayAttribute (2.x)
Another sometimes useful attribute is
DebuggerDisplayAttribute (docs).
This attribute is applied to a class and allows a custom string to be displayed
when instances of the type are moused over during a debugging session. By
default, the type of the variable is shown, or if the .ToString() method has
been overridden, the result of the .ToString() method is shown. Thus, there is
no need to use this attribute if the .ToString() method will show what you want
to see. One interesting thing to note about this attribute is that it can
include both literal string data and expressions using the object's members.
For example, the expression "Name = {Name}" would display the
following when Name = "Steve":
In addition to controlling what you see when you mouse over
an instance of the type, the DebuggerDisplayAttribute also affects the Value
shown in the Locals window. For instance, by modifying the Person2 class to
include the attribute as shown in Listing 5, we can get the view shown in
Figure 3 (compare its Value for myPerson with Figure 2 above).
Listing 5
[DebuggerDisplay("Person2: {Name}")]
class Person2
{
…
}
Figure 3