Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Professional Visual Studio 2005 (2006) [eng]

.pdf
Скачиваний:
132
Добавлен:
16.08.2013
Размер:
21.9 Mб
Скачать

Chapter 49

Adding Break Conditions

While breakpoints are useful for pausing an application at a given point to review variables and watch application flow, if you are looking for a particular scenario it may be necessary to break only when certain conditions are valid. Breakpoints can be tailored to search for particular conditions, to break after a number of iterations, or even be filtered based on process or machine name.

Condition

A breakpoint condition can be specified by selecting Condition from the Breakpoint item on the right-click context menu for the breakpoint. This brings up the Breakpoint Condition dialog shown in Figure 49-6, which accepts a Boolean condition that determines whether the breakpoint will be hit. If the condition evaluates to false, the application continues past the breakpoint without breaking.

Figure 49-6

In the case of Figure 49-6, which is for a breakpoint set within the Customer class, the condition specifies that the customer’s name must be Bob. As with most debugging windows, the Condition field provides rich IntelliSense support to aid writing valid conditions. If an invalid condition is specified, the debugger throws an appropriate error message and the application will break the first time the breakpoint is reached.

When a condition, or a Hit Count, as shown in the next section, is placed on a breakpoint, the breakpoint changes appearance. The solid red dot is replaced with a red dot with a white cross. When you move your mouse across this dot, the tooltip provides useful information about the breakpoint condition, as illustrated in Figure 49-7.

Figure 49-7

Sometimes it is more relevant to know when this condition changes status, rather than when it is true. The Has Changed option will break the application when the status of the condition changes. If this option is selected, then the application will not break the first time the breakpoint is hit, as there is no previous status to compare against.

706

Debugging Breakpoints

Using multiple breakpoints with complex conditions can significantly slow down the execution of your application, so it is recommended that you remove breakpoints that are no longer relevant in order to speed up the running of your application.

Hit Count

Perhaps not as useful as breakpoint conditions, it is also possible to break after a particular number of iterations through a breakpoint. To do this, select Hit Count from the Breakpoint item on the right-click context menu. Figure 49-8 shows the Breakpoint Hit Count dialog, which can be used to specify when the breakpoint should be hit.

Figure 49-8

Every time the application is run, the hit counter is reset to zero, and it can be manually reset using the Reset button. The hit counter is also unique to each breakpoint. The hit count condition is one of four options:

Always: Disregard the hit counter.

Is equal to: Break if the hit counter is equal to the value specified.

Multiple of: Break if the hit counter is a multiple of the value specified (as shown in Figure 49-7).

Is greater than or equal to: Break if the hit counter is greater than or equal to the value specified.

Figure 49-9 shows the Breakpoints window, which provides additional information about the status of each of the breakpoints. In this case, the breakpoint is set to break every second time. The current hit counter is 4.

Figure 49-9

Filter

A single solution may contain multiple applications that need to be run at the same time. This is a common scenario when building a multi-tier application. When the application is run, the debugger can attach to all of these processes, enabling them to be debugged. By default, when a breakpoint is reached all the processes will break. This behavior can be controlled from the Debugging (General) node in the Options window, accessible from the Options item on the Tools menu. Unchecking the “Break all processes when one process breaks” checkbox enables processes to be debugged individually.

707

Chapter 49

If a breakpoint is set in a class library that is used by more than one process, each process will break when it reaches that breakpoint. Because you might only be interested in debugging one of these processes, you can place a filter on the breakpoint that limits it to the process you are interested in. If you are debugging applications on multiple machines, then it is also possible to specify a machine name filter.

In fact, filtering can be useful for a multi-threaded application for which you want to limit the breakpoints to a particular thread. However, in this case, when the breakpoint is hit (such as when the current thread being executed meets the filter criteria), all threads are paused regardless of whether they meet the filter criteria. Figure 49-10 shows the Breakpoint Filter dialog and the possible filter conditions.

Figure 49-10

Working with Breakpoints

It’s often necessary to adjust a breakpoint, as it might be in the wrong location or no longer relevant. In most cases it is easiest to remove the breakpoint, but in some cases — for example, when you have a complex breakpoint condition — it might be necessary to adjust the existing breakpoint.

Deleting

To remove a breakpoint that is no longer required, select it, either in the code editor or in the Breakpoints window, and remove it using the Toggle Breakpoint item from the Debug menu. Alternatively, the Delete Breakpoint item from the right-click context menu or the Delete Breakpoint icon from the Breakpoints window toolbar will remove the breakpoint.

Disable

Instead of deleting a breakpoint, simply disabling the breakpoint can be useful when you have a breakpoint condition set or you are tracking a hit count. To disable a breakpoint, select it either in the code editor or in the Breakpoints window, and disable it using the Disable Breakpoint item from the right-click context menu. Alternatively, you can uncheck the checkbox against the breakpoint in the Breakpoints window. Figure 49-11 shows how a disabled breakpoint would appear in the code window.

Changing Location

The location of a breakpoint can be modified by selecting Location from the Breakpoint item on the right-click context menu. Depending on what type of breakpoint has been set, the dialog shows the location of the breakpoint as either a line and character position in a file or function, or as an address within

708

Debugging Breakpoints

an assembly. If the location is either a file or function position, the breakpoint can be adjusted so it is in the correct location. Address breakpoints are harder to relocate, as you need to ensure that the new address is a valid location for a breakpoint.

Figure 49-11

Tracepoints

A tracepoint differs from a breakpoint in that it triggers an additional action when it is hit. In fact, for purposes such as applying filters, conditions, and hit counts, a tracepoint can be thought of as a breakpoint.

Tracepoints can be compared to using either Debug or Trace statements in your code, but tracepoints can be dynamically set as the application is being debugged and do not affect your code.

Creating a Tracepoint

Tracepoints can be created from either an existing breakpoint or the Breakpoint right-click context menu. To create a tracepoint from an existing breakpoint, select When Hit from the Breakpoint right-click context menu. The resulting dialog, shown in Figure 49-12, gives you the option of printing a message to the console window or running a macro. Alternatively, to create a tracepoint at a new location, select Insert Tracepoint from the Breakpoint item on the right-click context menu. This again loads the dialog shown in Figure 49-12 so you can customize the tracepoint action.

Figure 49-12

709

Chapter 49

Once you set a tracepoint, the code window changes the appearance of that line of code to indicate that a tracepoint has been set. This is shown in Figure 49-13, where the tracepoint appears with a diamond in the margin. (The diamond is red, although this can’t be seen in the figure.)

Figure 49-13

Tracepoint Actions

Two types of actions can be performed when a tracepoint is hit: either print a message to the console window or run a macro. In the dialog shown in Figure 49-12, you can indicate which action should be run when the tracepoint is hit. If both actions are unchecked, the tracepoint will fall back to being a breakpoint.

By default, once a tracepoint action has been indicated, the Continue Execution checkbox will be checked so the application will not break at this point. Unchecking this option causes the application to break at the tracepoint as if it were a breakpoint. The action defined will be performed prior to the application breaking. The appearance of this tracepoint will be the same as that of a breakpoint, as the visual cue indicates that the debugger will not stop at the tracepoint, rather than indicate that there are actions associated with the tracepoint.

Output Messages

As the dialog in Figure 49-12 suggests, a number of keywords can be used in conjunction with your trace message. However, a couple of keywords are not listed by the dialog: $FILEPOS, which gives the location of the current file, and $TICKS, which can be used as a relative time indicator.

Macros

Tracepoints can execute any Visual Studio macro, which includes macros you may have created. Because macros can be used to modify source code, be careful which macros you execute within a tracepoint. Modifying code while debugging an application may result in the source code being out of sync with the running application.

Execution Point

After reaching a breakpoint, it is often useful to be able to step through code and review both variable values and program execution. Visual Studio 2005 not only enables you to step through your code, it also permits you to adjust the execution point to backtrack or even repeat operations. The line of code that is about to be executed is highlighted, as shown in Figure 49-14. (The highlighting is yellow, which can’t be seen in the figure, of course.)

710

Debugging Breakpoints

Figure 49-14

Stepping Through Code

The first step in manipulating the execution point is simply to step through code in the expected order of execution. Three size increments can be used to step the debugger forward. It is important to remember that when stepping through code it is actually being run, so variable values may change as you progress through the application.

Stepping Over (F10)

Stepping Over is fully executing the line that currently has focus and progressing to the next line in the current code block. If the end of the code block has been reached, stepping returns to the calling code block.

Stepping In (F11)

Stepping In behaves the same as Stepping Over when the line is a simple operator, such as a numeric operation or a cast. When the line is more complex, Stepping In steps through all user code. For example, in the following code snippet, pressing F10 through the TestMethod only steps through the lines of code within TestMethod. Pressing F11 steps through TestMethod until the MethodA call is made, and then the debugger steps through MethodA before returning to TestMethod:

Public Sub TestMethod()

Dim x As Integer x = 5 + 5 MethodA()

End Sub

Public Sub MethodA()

Console.WriteLine(“Method A being executed”)

End Sub

Stepping Out (Shift+F11)

If you step into a long method by accident, it is quite often convenient to be able to step back out of that method without having to either step over every line in that method or setting a breakpoint at the end of the method. Stepping Out moves the cursor out of the current method to where it was being called.

Considering the previous snippet, if you entered MethodA, pressing Shift+F11 would immediately return the cursor to the end of TestMethod.

711

Chapter 49

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 rewind the last action. While you can’t do that entirely, 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 49-12) forward or backward in the current method. Use this functionality with care, as it can result in unintended behavior and variable values.

Edit and Continue

One of the features of Visual Studio 2005 that a lot of developers have been waiting for is Edit and Continue. The good news is that both C# and VB.NET 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 there are any limitations 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 2005 help resource, 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

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 might take some time. If you wish to cancel this action, you can select Stop Applying Code Changes from the Debug menu.

712

Debugging Breakpoints

Summar y

Most developers who use Visual Studio 2005 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 the various debugging windows that become active when the application is in Break mode. These enable you to probe variable values, identify and manage threads, as well as work with the Call Stack window.

713

Debugging Proxies

and Visualizers

Other than writing code, debugging is likely the most time-consuming activity when writing an application. If you think about 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 complex and 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.

Attributes

This section begins by outlining a number of debugging attributes that can be applied to code to affect the way the debugger steps through it. In addition, some attributes can be used to customize the appearance of your types when you hover over them in Break mode.

DebuggerBrowsable

The first attribute you can apply to fields and properties that belong to a C# class is the DebuggerBrowsable attribute. Although this attribute can be applied to both C# and VB.NET code, it is only interpreted by the C# debugger. This 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: