VB: Customer.vbClass Customer Property Discount As Decimal Property Order As Order Function GetOrderDiscount As Decimal Return Order.Total * Discount End Function End Class V
Trang 1Debugging with
Visual Studio
Trang 2Key Skills & Concepts
● Exploring Available Debugging Tools
● Setting Breakpoints
● Inspecting Program State
● Solving Problems with VS Debugging Tools
More often than we would like, our code has bugs Fortunately, when bugs do happen,
you have a lot of help with VS This chapter shows you how to use the VS debugger
to fix problems by setting breakpoints, stepping through code, and inspecting program state There’s also a section on development-time tools to inspect the structure of your code Beyond setting breakpoints, you’ll learn how to customize breakpoints and how
to manage a list of breakpoints Then you’ll see the options VS has for stepping through code This chapter also shows you many ways to see what the values of variables are in your code and the various tools available for inspecting your code First, we’ll start with some example code you can use to practice the concepts learned in this chapter
Example Code for This Chapter
It would take many pages of code to show a complete program with all of the complexity
of a real-world scenario, which might be hard to follow for the purposes of this chapter So, the example you’ll see simulates the environment of a full application When performing debugging, you’ll need to traverse hierarchies in code, where one method calls another, which could go multiple levels deep, depending on the program The example code will have multiple levels of method calls so that you can see how to use VS to debug code Listing 6-1 shows the example code for this chapter It’s a console application, just like all of the applications created in previous chapters You create a console project by selecting File | New | Project, select the Console Application project, give the project a name, and generate the project by clicking OK The application in Listing 6-1 calculates
a discount for a customer, based on a special discount percentage for that customer and what that customer ordered
Trang 3Listing 6-1 Example code for chapter
C#: Program.cs
using System;
namespace DebugAndTestDemo
{
class Program
{
static void Main()
{
Customer cust = new Customer();
cust.Discount = 1m;
Order ord = new Order();
ord.AddItem(5.00m);
ord.AddItem(2.50m);
cust.Order = ord;
decimal discount = cust.GetOrderDiscount();
Console.WriteLine("Customer Discount: {0}", discount);
Console.ReadKey();
}
}
}
C#: Customer.cs
namespace DebugAndTestDemo
{
class Customer
{
public decimal Discount { get; set; }
public Order Order { get; set; }
public decimal GetOrderDiscount()
{
return Order.Total * Discount;
}
}
}
C#: Order.cs
using System.Collections.Generic;
Trang 4namespace DebugAndTestDemo
{
class Order
{
private List<decimal> orderItems = new List<decimal>(); public decimal Total
{
get
{
decimal amount = 0;
foreach (var item in orderItems)
{
amount = amount + item;
}
return amount;
}
}
public void AddItem(decimal amount)
{
orderItems.Add(amount);
}
}
}
VB: Module1.vb
Module Module1
Sub Main()
Dim cust As Customer = New Customer()
cust.Discount = 0.1D
Dim ord As Order = New Order()
ord.AddItem(5D)
ord.AddItem(2.5D)
cust.Order = ord
Dim discount As Decimal = cust.GetOrderDiscount() Console.WriteLine("Customer Discount: {0}", discount) Console.ReadKey()
End Sub
End Module
Trang 5VB: Customer.vb
Class Customer
Property Discount As Decimal
Property Order As Order
Function GetOrderDiscount() As Decimal
Return Order.Total * Discount
End Function
End Class
VB: Order.vb
Class Order
Private orderItems As New List(Of Decimal)
Public ReadOnly Property Total() As Decimal
Get
Dim amount As Decimal = 0
For Each item In orderItems
amount = amount + item
Next
Return amount
End Get
End Property
Sub AddItem(ByVal item As Decimal)
orderItems.Add(item)
End Sub
End Class
A quick look at the code in Listing 6-1 tells you that this program is more sophisticated
than the examples you’ve encountered in previous chapters To understand what is happening,
start at the Main method, the entry point of the application There are two objects instantiated
in Main, namely Customer and Order.
After instantiating Customer, you can see that the Discount property on cust is being
set to 1 (10%) This means that each instance of Customer can have a unique discount
amount, which could be useful if you wanted to reward good shopping habits
Next, you can see the instantiation of Order and subsequent calls to AddItem on the
object reference ord This code only adds the order amount, but in a real scenario it
would likely be a class with more fields to carry the specific details of the order item The
Customer class has an Order property, which the code then passes our Order instance,
ord, to Now, you have a Customer with a discount amount and it has a reference to our
specific Order, which in turn has items (represented here by the items’ monetary amount
only for brevity)
Trang 6This program calculates the total monetary discount that a customer would receive for that
order by calling the GetOrderDiscount method on the Customer instance, which then returns
the calculated discount amount to be subsequently displayed on the console Essentially, we
created a couple of object instances, cust and ord, gave the object instances the data they
needed, and told the object instances to do some work for us The result is a special discount monetary amount for a given customer, based on the customer’s items ordered
All of the code in the Main method is at the first level of the call hierarchy The methods and properties in Customer and Order are at the second level of the hierarchy Looking at Order, you can see that there is a Total property and an AddItem method
AddItem adds the item parameter to its orderItems collection Total iterates through the
orderItems collection, first calculating then returning the sum of all items Notice that the
Customer class has a Discount property that holds a decimal value that will be used as a percentage The GetOrderDiscount method in Customer multiplies the Discount by the
Total in Order to return the discount of the order.
It’s important for you to study this example and understand the relationships and communication between various objects Observe that each class has a distinct purpose, relating to how it is named The purpose of the class helps decide what data and methods
that class will have; Order has Total and AddItem, and the class Customer has Discount and GetOrderDiscount Each object communicates with other objects, cooperating
to perform a task For example, it is Customer’s responsibility to calculate a discount because the Customer class knows what the discount should be (because we told it what the discount was in Main) However, Customer must communicate with Order because
Order is the only object that knows about the order items and how to calculate the total Although I’ve shown you the code and explained how it works, it’s often useful to see the flow of logic of the actual running program yourself VS includes various visualization and debugging tools that help you understand the flow of logic, which are discussed next
Development-Time Code Tools
One of the new features of VS 2010 is Call Hierarchy, which allows you to see what code calls a method and which methods are being called by your code First, I’ll explain why call hierarchy is important, and then I’ll show you how to use it Figure 6-1 shows what the Call Hierarchy window looks like, and the following discussion will explain the motivation for and use of the Call Hierarchy feature
The call hierarchy tells you several things about code, including the degree of reuse, impact of a change, and potential importance of a routine To help understand the discussion,
a call site is code that invokes another class member For example, in Listing 6-1, the Main method is the call site and the GetOrderDiscount method is the called code.
Trang 7From the perspective of reuse, many call sites to a method could indicate that the
method is relatively generic and reusable While a low number of call sites might not
indicate the reusability of a method, zero call sites certainly indicates that the method is
not being used and can potentially be eliminated
A lot of call sites could also indicate that a change to a method can have a significant
impact Looking at the number of call sites that a method has could be informative from
the perspective of passing different values or seeing how many changes will be required in called methods
The previous discussion is to help you understand how call hierarchy might be
useful Now, let’s look at how call hierarchy works First, remember that call hierarchy
is context-sensitive, meaning that whatever code in the editor has focus defines your
point of view The point of view for this example will be the GetOrderDiscount method
in the Customer class, and we want to see the call sites of GetOrderDiscount and what
statements inside of GetOrderDiscount are call sites To use call hierarchy, either
right-click the GetOrderDiscount method in the editor and select View Call Hierarchy, or select
GetOrderDiscount in the editor and press CTRL-K, T VS shows the Call Hierarchy window
in Figure 6-1
The Call Hierarchy window in Figure 6-1 shows Calls To and Calls From for the
GetOrderDiscount method Calls To is a list of call sites to the GetOrderDiscount method
Calls From is a list of statements within GetOrderDiscount that are call sites for other
class members
The drop-down list at the top left of Figure 6-1, with My Solution selected, identifies
how far Call Hierarchy will look to find Calls To and Calls From call sites The options
are My Solution, Current Project, and Current Document, which are self-explanatory
Figure 6-1 The Call Hierarchy window
Trang 8If you’ve been working on your code and want to update the Call Hierarchy window, click Refresh Every time you view Call Hierarchy, the selected item is added to the list You can use the Remove Root button to delete an item from the list The Toggle Details Pane button shows and hides the Details pane, which shows the code and location of the call site
In Figure 6-1, the Main method is selected, which shows the call to GetOrderDiscounts off the cust instance of Customer from Listing 6-1 The actual code line is shown also You can
double-click the statement to navigate the editor to the location of that statement In fact, you can double-click any call site in the Call Hierarchy to navigate to the location of the call site
in the editor
The Call Hierarchy shows all of the possible paths you can take through a specific point in code While quite useful, it’s limited to providing a static view of your code, and
it does not provide the detailed insight into your running program that debugging may require When debugging, you typically need to view the running state of an application at
a specific point in time The following sections show you various features of the debugger that help you inspect the runtime behavior of code
Configuring Debug Mode
By default, VS creates projects with Debug mode enabled, which specifies project settings that make it possible for you to debug your application The VS toolbar shows you the current configuration settings you’re using; clicking the drop-down list will show Debug and Release configurations The Release configuration defines settings for your program that you want to use when you deploy it for production (actual) use You can also create
a custom configuration that allows you to set project properties how you want For the purposes of this chapter, we will use the Debug configuration
To understand what the Debug configuration gives you, ensure that the Debug configuration
is selected in the toolbar; you’ll need to have a project open to do this Then double-click the properties folder of your project and click the Build tab as shown in Figure 6-2
Figure 6-2 shows that optimizations are turned off and both TRACE and DEBUG are
defined Figure 6-2 shows the properties for a C# project, but in VB, the tab is called Compile When optimizations are turned on, the compiler will perform extra processing
on the code that makes it smaller and faster, altering the structure of the code When debugging, you don’t want optimizations because you need the code you’re stepping through to match what the compiler produces Compiler constants (also known as
compiler directives) such as TRACE and DEBUG are used by the compiler to enable or
disable blocks of code For example, the System.Diagnostics namespace has a Debug
class that will only work if DEBUG is defined.