stepping into them while debugging. This debugger option is especially useful if you are calling a
method that passes a number of properties as parameters, such as the method call listed here:
c#
printShippingLabel(cust.name, shipTo.street, shipTo.city, shipTo.state,
shipTo.zipCode);
With the Step Over Properties and Operators option enabled, the debugger steps directly into the
first line of the printShippingLabel method if you hit F11. If you need to, you can manually step
into a specific property by right-clicking the code editor window and selecting Step Into Specific.
This displays a submenu with each of the available properties listed, as shown in Figure 40-17.
edit and Continue .
855
fiGure 40-17
The Step Over Properties and Operators option is enabled by default. You can enable or disable it
during debugging by right-clicking anywhere in the code editor window and selecting it from the
context menu, or from the Options dialog window (Tools . Options, then select Debugging from
the treeview on the left-hand side).
Moving the execution Point
As you become familiar with stepping in and out of functions, you will find that you are
occasionally overzealous and accidentally step over the method call you are interested in. In this
case, what you really want to do is go back and review the last action. Though you can’t actually
unwind the code and change the application back to its previous state, you can move the execution
point so the method is reevaluated.
To move the current execution point, select and drag the yellow arrow next to the current line of
execution (refer to Figure 40-16) forward or backward in the current method. Use this functionality
with care, because it can result in unintended behavior and variable values.
edit and continue
One of the most useful features of Visual Studio 2010 debugging is Edit and Continue. Both C# and
Visual Basic have support for Edit and Continue, enabling you to make changes to your application
on the fly. Whenever your application is paused, you can make changes to your code and then
resume execution. The new or modified code is dynamically added to your application, with the
changes taking immediate effect.
rude edits
At this point, you are likely wondering whether any limitations exist on the changes that you can
make. The answer is yes, and there are quite a few types of rude edits, which refer to any code change
that requires the application to be stopped and rebuilt. A full list of rude edits is available from the
Visual Studio 2010 help resource under the Edit and Continue topic, but they include the following:
.
Making changes to the current, or active, statement
.
Changes to the list of global symbols — such as new types or methods — or changing the
signatures of methods, events, or properties
.
Changes to attributes
856 .
chaPter 40 debugging WiTh breAkpoinTS
stop applying changes
When changes are made to the source code while the application is paused, Visual Studio has to
integrate, or apply, the changes into the running application. Depending on the type or complexity
of the changes made, this could take some time. If you want to cancel this action, you can select
Stop Applying Code Changes from the Debug menu.
suMMary
Most developers who use Visual Studio 2010 will use breakpoints to track down issues with their
application. In this chapter, you learned how to optimize the use of breakpoints to reduce the
amount of time spent locating the issue.
The following chapter examines data tips and explains how to create debugging proxy types and
visualizers. This allows you to customize the debugging experience and reduce the time spent
wading through unnecessary lines of code.
41
DataTips, Debug Proxies,
and Visualizers
what’s in this chaPter?
.
Inspecting the contents of your variables usingDataTips
.
Applying attributes to your classes and member variables to
customize the debugger behavior
.
Creating type proxies and visualizers to represent complex variables
and data types in a useful way within the debugger
Other than writing code, debugging is likely the most time-consuming activity when writing
an application. If you consider all the time you spend stepping through code, looking at the
Watch window to see the value of a variable, or even just running the application looking for
any exceptions being raised, you will realize that this is one of the most time-consuming parts
of writing software.
Previous chapters have focused on how you can use the various debugging windows to retrieve
information about the current status of your application, and how you can set breakpoints
and tracepoints to generate debugging information. This chapter goes beyond what is provided
out of the box, and looks at how you can customize the debugging experience to reduce the
time spent wading through unnecessary lines of code.
Using debugging proxy types and visualizers, you can represent complex variables and
data types in a useful way within the debugger. This allows you to filter out unnecessary
information and zero in on the most relevant properties of an object, thereby making it easier
to determine when your application is not functioning correctly and be able to trace the source
of the issue.
858 .
chaPter 41 dATATipS, debug proxieS, And ViSuAlizerS
datatiPs
You have many ways to inspect the value of variables
within Visual Studio while debugging. For many
types, the easiest way to inspect a variable is simply
fiGure 41-1
hover the mouse over it, which displays the value of
the variable in a DataTip. Figure 41-1 shows a DataTip for a string property.
In addition to viewing the value of the variable, you can right-click the DataTip and perform a
number of actions. These include copying the value that is being displayed, adding the variable to
the Watch window, or even editing the current value of the variable in the case of simple types such
as strings or integers.
One new feature of Visual Studio 2010 is the introduction of pinned and floating DataTips. You
can think of these as the electronic equivalents of Post-It notes for Visual Studio. To create a pinned
DataTip, click the pin icon in the right-hand side of the DataTip. The DataTip will now stay pinned
to that line of code in the source file of the code editor and will become visible anytime a debugging
session is underway.
Figure 41-2 shows a Visual Studio workspace with two pinned DataTips for the variables
c.CustomerName and o1.Total. A menu will appear when you hover over a pinned DataTip.
Clicking the icon with double arrows will display a text input field below the DataTip where you
can enter some text. You can also click the pin icon in the menu to covert the pinned DataTip to a
floating DataTip. The DataTip for the c variable in Figure 41-2 is a floating DataTip.
fiGure 41-2
You can drag a pinned DataTip to any line of code in the source file to which it has been pinned, but
not anywhere outside of the code editor window. Pinned DataTips will also disappear if you switch
to a different source code file. Floating DataTips, on the other hand, are always visible during a
debugging session and can be dragged to any location on your monitor.
A blue pin icon will appear in the margin of the code editor for each pinned DataTip. This icon will
still be visible once the debug session has finished; you can hover the mouse over it and the DataTip
will appear with the value during the last debug session.
Debugger attributes .
859
You can close an individual pinned or floating DataTip by clicking the x icon, or close all of them by
selecting Debug . Clear All DataTips from the menu. You will also see a menu option to clear all
DataTips pinned to the current source file in the code editor if it contains any.
Finally, DataTips can be imported and exported to an external XML file, which can be useful for
backup purposes, or sharing them among developers. This is done by selecting Import DataTips or
Export DataTips from the Debug menu.
debuGGer attributes
This section outlines a number of debugging attributes that can be applied to code to affect the way
the debugger steps through it. Some of the debugging attributes can also be used to customize the
appearance of your types when you hover over them in Break mode.
The debugging attribute classes are contained within the System.Diagnostics
namespace. Rather than specify the full namespace for each attribute, the source
code examples in this chapter assume that it has been added as an import.
debuggerbrowsable
The first attribute you can apply to fields and properties is the DebuggerBrowsable attribute. In
.NET Framework 2.0, this attribute was only interpreted by the C# debugger and had no effect
when applied to Visual Basic code. This limitation has been removed in newer versions of the .NET
Framework. The DebuggerBrowsable attribute takes a single parameter that determines how the
member is displayed in the variable tree. In the following code snippet, the field Orders is set to
Collapsed:
c#
public class Customer
{
[DebuggerBrowsable(DebuggerBrowsableState.Collapsed)]
public List < Order > Orders;
}
Vb
Public Class Customer
< DebuggerBrowsable(DebuggerBrowsableState.Collapsed) > _
Public Orders As List(Of Order)
End Class
Figure 41-3 (left) shows the same snippet of code with DebuggerBrowsable initially set to
Collapsed (or not specified). Figure 41-3 (center) shows the same snippet with DebuggerBrowsable
860 .
chaPter 41 dATATipS, debug proxieS, And ViSuAlizerS
set to the RootHidden value, where the actual Orders item does not appear, just the contents of the
collection. Finally, in Figure 41-3 (right) the Never value is used for DebuggerBrowsable, in which
case the Orders member does not appear at all.
fiGure 41-3
debuggerdisplay
When you hover your mouse over a variable while you are in Break mode, the first thing you will
see in the tooltip is the type of object you are hovering over. In Figure 41-3, a mouse was initially
hovering over the Customer class, followed by the Order class. This information is not particularly
useful, because most of the time you have a fairly good idea about the type of object you are
dealing with. It would be better for this single line to contain more useful information about the
object. This is the case for well-known types, such as strings and integers, where the actual value is
displayed.
The DebuggerDisplay attribute can be used to change the single-line representation of the object
from the default full class name. This attribute takes a single parameter, which is a string. The
format of this string can accept member injections using the String.Format breakout syntax. For
example, the attributes applied to the Customer and Order classes might be as follows:
c#
[DebuggerDisplay("Customer {CustomerName} has {Orders.Count} orders")]
public class Customer
[DebuggerDisplay("Order made on {DateOrdered} which is worth ${Total}")]
public class Order
Vb
<DebuggerDisplay("Customer {CustomerName} has {Orders.Count} orders")> _
Public Class Customer
<DebuggerDisplay("Order made on {DateOrdered} which is worth ${Total}")> _
Public Class Order
This would give you the debugger output shown
in Figure 41-4, which indicates that customer
Michael McManus has one order, which, as you
can see from the description, was made on April 4
and is worth $120.
fiGure 41-4
Debugger attributes .
861
Looking back at the syntax for the DebuggerDisplay attribute, you can see that the output string
consists of both static text and field and property information from the object. For example, the
CustomerName property for the Customer object is referenced using the {CustomerName} syntax
within the static text.
debuggerhidden
The DebuggerHidden attribute can be added to code that you don’t want to step through when
debugging. Code marked with this attribute is stepped over and does not support breakpoints. If
this code makes a call to another method, the debugger steps into that method. Taking the following
code snippet, a breakpoint can be set in both ClickHandler and NotSoHiddenMethod:
c#
private void ClickHandler(object sender, EventArgs e)
{
HiddenMethod();
}
[DebuggerHidden()]
public void HiddenMethod()
{
Console.WriteLine("Can't set a breakpoint here");
NotSoHiddenMethod();
}
public void NotSoHiddenMethod()
{
Console.WriteLine("Can set a breakpoint here!");
}
Vb
Private Sub ClickHandler(ByVal sender As Object, ByVal e As EventArgs)
HiddenMethod()
End Sub
<DebuggerHidden()> _
Public Sub HiddenMethod()
Console.WriteLine("Can't set a breakpoint here")
NotSoHiddenMethod()
End Sub
Public Sub NotSoHiddenMethod()
Console.WriteLine("Can set a breakpoint here!")
End Sub
If you step through this code, the debugger goes from the call to HiddenMethod in the ClickHandler
method straight to NotSoHiddenMethod.
The call stack at this point is shown in
Figure 41-5, and you can see that
HiddenMethod does not appear in the stack.
fiGure 41-5
862 .
chaPter 41 dATATipS, debug proxieS, And ViSuAlizerS
As with all of the System.Diagnostic attributes, the CLR will ignore this, so you will still see the
method call in the stack trace of any exceptions thrown at run time.
debuggerstepthrough
Like the DebuggerHidden attribute, when the DebuggerStepThrough attribute is applied to a piece
of code, that code is stepped over when debugging, regardless of whether this code calls other
methods.
Similar to the DebuggerHidden attribute, breakpoints cannot be set within a block of code marked
with the DebuggerStepThrough attribute. However, if a breakpoint is set within a section of code