1. Trang chủ
  2. » Công Nghệ Thông Tin

Visual studio 2010 part 20 ppsx

15 196 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 15
Dung lượng 238,54 KB

Nội dung

166 Microsoft Visual Studio 2010: A Beginner’s Guide IntelliTrace could be useful if you stepped over a statement that changed the value of a variable and needed to go back to see what the variable value was before you stepped. Figure 6-15 shows this scenario, where the highlighted event, Breakpoint hit: Main, allows you to view Locals or Call Stack. The important distinction is that the values shown are for the point in time when that event occurred, not the current time, which can be very valuable information. Another important application of IntelliTrace is to inspect IntelliTrace log files that were produced by another developer or the new Microsoft Test and Lab tool that records a tester’s testing session. You can configure IntelliTrace options by selecting Tools | Options | IntelliTrace. IntelliTrace will create a log file that exists as long as VS is running. When VS stops, the log file is deleted, so it’s important that you copy this file before shutting down VS. The location of the log file is on the Advanced branch of IntelliTrace in Tools | Options. If you receive a log file from another developer, you can load it by selecting File | Open | Open New. Then you can view debugging history to view the state of the application during each event of the session. Solving Problems with VS Debugger Previously, you’ve seen how the VS tools work and gathered a few tips on debugging. This section builds upon what you’ve learned and steps you through a couple of real-world scenarios that demonstrate how to use the VS debugger to solve problems: finding and Figure 6-15 The Debug History window Chapter 6: Debugging with Visual Studio 167 handling bad data and fixing null references. The program itself is not particularly sophisticated, but it contains just enough logic to lead you down a rat hole and show you how to work your way out. First, we’ll look at the program, and then we’ll follow up with two bug-fixing exercises. A Program with Bugs The code in this section contains bugs, and it’s important that you type it in as listed or use the downloadable code for this book from the McGraw-Hill Web site. I’ll describe each piece of code and try not to give away all of the secrets of the bugs just yet. Later, I’ll guide you through a process of discovery to find and fix the bugs. The program is a search application that takes the first name of a person and searches for that person through a list of customers. If the program finds the customer being searched for, it will print the customer’s first and last name. Otherwise, the program will print a message stating that it did not find the customer. The program is divided into three major parts: a class to hold customer information, a class that will return a list of customers, and the class containing the Main method that runs the program. The following sections describe each of these classes. The Customer Class Any time you are working with data, you’ll have a class to hold that data. Since this application works with customers, the natural approach is to have a Customer class, as follows: C#: public class Customer { public string FirstName { get; set; } public string LastName { get; set; } } VB: Public Class Customer Property FirstName As String Property LastName As String End Class This is the minimal information required for this demo, and any class that you build will have more properties. Notice that both properties are type string. 168 Microsoft Visual Studio 2010: A Beginner’s Guide The CustomerRepository Class In this program, we create a class that is solely responsible for working with data. This is a common pattern, which is called the Repository pattern. The following CustomerRepository class has a method that returns a list of Customer objects: C#: using System.Collections.Generic; public class CustomerRepository { public List<Customer> GetCustomers() { var customers = new List<Customer> { new Customer { FirstName = "Franz", LastName = "Smith" }, new Customer { FirstName = "Jean " }, new Customer { FirstName = "Wim", LastName = "Meister" } }; return customers; } } VB: Public Class CustomerRepository Public Function GetCustomers() As List(Of Customer) Dim customers As New List(Of Customer) From { New Customer With { .FirstName = "Franz", .LastName = "Smith" }, New Customer With Chapter 6: Debugging with Visual Studio 169 { .FirstName = "Jean " }, New Customer With { .FirstName = "Wim", .LastName = "Meister" } } Return customers End Function End Class The GetCustomers method returns a List<Customer> (List(Of Customer) in VB). For the purposes of this discussion, how the GetCustomers method works won’t matter. Such a method could easily get customers from a database, Web service, or other object. For simplicity, GetCustomers initializes a List with Customer objects. The part of this method that is particularly important is the customer whose FirstName property is set to “Jean ”. Notice the blank space appended to the name, which is required to make this scenario behave as designed (i.e., to intentionally create a bug). It’s also conspicuous that the Customer object with a FirstName property set to “Jean ” also does not have a LastName. The Program with Bugs The following is a search program that uses CustomerRepository to get a list of Customer objects. The logic will iterate through the results, checking to see if the result is equal to the search term. When the result is equal, the program prints the full name of the customer. If no matching customers are found, the program indicates that the customer wasn’t found: C#: using System; class Program { static void Main() { var custRep = new CustomerRepository(); var customers = custRep.GetCustomers(); var searchName = "Jean"; bool customerFound = false; 170 Microsoft Visual Studio 2010: A Beginner’s Guide foreach (var cust in customers) { // 1. First Bug if (searchName == cust.FirstName) { Console.WriteLine( "Found: {0} {1}", cust.FirstName, cust.LastName); customerFound = true; } } if (!customerFound) { Console.WriteLine("Didn't find customer."); } Console.ReadKey(); } } VB: Module Module1 Sub Main() Dim custRep As New CustomerRepository Dim customers As List(Of Customer) customers = custRep.GetCustomers() Dim searchName As String = "Jean" Dim customerFound As Boolean = False For Each cust As Customer In customers ' 1. First Bug If (searchName = cust.FirstName) Then Console.WriteLine( "Found: {0} {1}", cust.FirstName, cust.LastName) customerFound = True End If Next Chapter 6: Debugging with Visual Studio 171 If (customerFound = False) Then Console.WriteLine("Didn't find customer.") End If Console.ReadKey() End Sub End Module Notice that the searchName variable is set to “Jean”. Within the loop, the searchName is compared with the FirstName property of each Customer instance for equality. Here’s the output from when the program runs: Didn't find customer. What is supposed to happen is that the program should find the matching record and print it out, but that’s not what happens. Here is the first bug, and the following discussion describes how to find the cause of the bug using the VS debugger. Finding the Bug At this point, we know there is a bug and it’s reproducible, meaning that we can use VS to debug and find the cause of the problem. In this situation, the program is saying that it didn’t find a Customer record or, in other words, there is no record with a FirstName of Jean. However, we know for a fact that the data does include a customer whose FirstName is Jean. We need to find out why the program cannot find it. The following steps show how the VS debugger can help isolate the problem. 1. Start by setting a breakpoint on the foreach loop in the Main method. This wasn’t an arbitrary decision. Instead, considering the nature of the problem, I selected a part of the program that is likely to begin providing a cue to what the problem is. Looking at the program, one of the reasons that the program might not find the searchName is that we aren’t getting data, causing the program to not execute the body of the foreach loop. 2. Press F5 to run the program in debug mode. This will execute the program and make it stop on the foreach loop, making it possible to look at program state. 3. After VS hits the breakpoint, hover over customers to see if there are any values. You’ll observe that customers does have three values. The fact that there are customers indicates that the foreach loop is executing and we’ve eliminated that as a possibility. 172 Microsoft Visual Studio 2010: A Beginner’s Guide 4. Next, set a breakpoint on the if statement, right-click the breakpoint, and set the condition as follows: C#: cust.FirstName == "Jean" VB: cust.FirstName = "Jean" The goal here is to see what happens when the if statement finds the record matching the searchName. At this point, we’re assuming that Jean does exist in the data. Working with a small program, you can use windows such as Autos, Locals, or Watch to find this record. However, many real-world scenarios will give you a list with many more records. Therefore, rather than waste time drilling down through dozens of records, use the VS debugger to help find the record quickly. Keep in mind that all the best plans don’t always work out, as you’ll soon see, but the primary point is taking the most productive step first. Setting a conditional breakpoint demonstrates how you can set conditions that can avoid eating up time caused by stepping through loops. 5. Press F5 to run the program. You expect to hit the breakpoint, but that won’t happen. Confusing? We know that there isn’t anything wrong with the logic, because the if statement condition is a simple equality operator. Perhaps we’ve looked in the database or whatever source the data came from, but it’s given in this scenario that Jean is definitely in the data. However, this illustrates a common problem where the quality of data you work with is less than desired. 6. This time, change the breakpoint condition on the if statement as follows and re-run the program: C#: cust.FirstName.Contains("Jean") VB: cust.FirstName.Contains("Jean") Remember, we suspect bad data, so the call to Contains on the string assumes that there might be some extraneous white space or other characters around the name in the data. Hover over cust.FirstName or look at cust in one of the debug windows to verify it is the record you are looking for. This breakpoint will pause on any records that contain the sequence of characters “Jean”, such as Jean-Claude. So, you might have multiple matches that aren’t what you want. The benefit is that the number of records you must Chapter 6: Debugging with Visual Studio 173 look at is much fewer and you can save time. If you have multiple records, you can press F5 and the breakpoint will pause on each record, allowing you to inspect the value. In this case, the record set is so small that we hit the right record immediately. 7. Press F10 to step over the if condition. This will tell us whether the condition is being evaluated properly. In this case, VS does not step into the if statement but instead moves to the end of the if statement, meaning that searchName and cust.FirstName are not equal. This means you need to take a closer look at cust.FirstName to see what the problem is with the data. 8. Next, we’ll use a couple of the VS debugger tools to inspect cust.FirstName and find out why the equality check is not working. Open the Immediate window ( CTRL-D, I) and execute the following expression: cust.FirstName which will return this: "Jean " Here, you can see that the result has a trailing space—dirty data. Clearly, “Jean” does not equal “Jean ” because of the extra character in the data. There are various non- printable characters that could show up, and VS can help here too. 9. Open a Memory window (CTRL-D, Y), type cust.FirstName into the Address box, and press ENTER. This will show the hexadecimal representation of the data at the memory location of the variable, shown in Figure 6-16. The layout of the Memory window starts with an address on the left, which is scrolled down to the line where the data in cust.FirstName variable first appears. In the middle is the hex representation of the data. The final column has a readable Figure 6-16 The Memory window 174 Microsoft Visual Studio 2010: A Beginner’s Guide representation of the data where any characters that don’t have a readable representation appear as dots. You can see “.J.e.a.n.” on the first line of the third column. .NET characters are 16-bit Unicode, and the data for the character only fills the first byte, resulting in the second byte being set to 00, causing the dots between characters you see in the first column. If the data used another character set, such as Japanese Kanji, you would see data in both bytes of the character. The hex representation of this data in the second column is “00 4a 00 65 00 61 00 6e 00 20”. Looking at the Unicode representation, which you can find at http://unicode.org/, you’ll see that the hex and visual representation of the characters match. You can see that I’ve highlighted the 00 20 at the end of the first line of the second column in Figure 6-16, which proves that Jean is followed by a Unicode space character. Knowing this information might help you share information with someone who is responsible for the data, letting them know that there are extraneous spaces in the data. Some computer or software systems might even use other types of characters, perhaps a proprietary delimiter for separating data, and accidentally save the data with the delimiter. Fixing the First Bug While you might have bad data and it might not be your fault, the prospect of fixing the problem by fixing the data source is often illusive, meaning that you need to apply a fix in your code. In this section, we’ll apply a fix. However, we’ll put a convoluted twist in the solution where we discover a new bug when fixing the first. The purpose is twofold: to illustrate the real-world fact that there are often multiple problems with a given piece of code and to show a completely different type of bug that you will encounter when writing your own code. The following steps lead you through the fix and subsequent discovery of the new bug: 1. Press SHIFT-F5 to stop the previous debugging session. 2. Implement a fix by commenting out the contents of the foreach loop and replacing with code that protects against extraneous spaces in the data, as follows: C#: var firstName = cust.FirstName.Trim(); var lastName = cust.LastName.Trim(); if (searchName == cust.FirstName) Chapter 6: Debugging with Visual Studio 175 { Console.WriteLine( "Found: {0} {1}", firstName, lastName); customerFound = true; } VB: Dim firstName As String = cust.FirstName.Trim() Dim lastName As String = cust.LastName.Trim() If (searchName = cust.FirstName) Then Console.WriteLine( "Found: {0} {1}", cust.FirstName, cust.LastName) customerFound = True End If Next Notice that the fix was to use the string.Trim method to remove the extraneous space from the data, assigning the clean results to local variables. Trim defaults to using the space character but has overloads that allow you to specify a different character , just in case the actual character you saw in Figure 6-16 was something other than a space. The rest of the logic uses variables with the clean data. 3. Press F5 to run the program and see if the fix works. Unfortunately, you’re stopped in your tracks by the fact that a new error occurs: a NullReferenceException. Unlike runtime errors that give you wrong data, VS helps greatly by breaking on exceptions when they occur in the code. The next section describes this error, the NullReferenceException, in greater detail and provides information to help you deal with the problem when it occurs in your programs. Debugging and Resolving NullReferenceException Problems Encountering a NullReferenceException in your code is a common occurrence, deserving some discussion to help you deal with these problems effectively. As described in Step 3 in the preceding section, VS will pause on a NullReferenceException when running [...]...176 Microsoft Visual Studio 201 0: A Beginner’s Guide the program In this particular example, VS pauses on the line that cleans LastName properties, repeated here for your convenience: C#: var firstName = cust.FirstName.Trim(); var lastName = cust.LastName.Trim();... but my point is that you should think about what working with a null value means to your particular situation and not think that the only way to fix a null reference bug is the way we did here 8 Press F5 to run the program It will provide the following output: Found: Jean Victory! 179 180 Microsoft Visual Studio 201 0: A Beginner’s Guide Summary You are now able to debug code The section “Development-Time... to inspect the data to see if it is the source of the null data by typing the following command into the Immediate window: C#: customers[1].LastName VB: ?customers(1).LastName 177 178 Microsoft Visual Studio 201 0: A Beginner’s Guide Additionally, you can drill down into the customers collection in one of the debugging windows, such as Autos, Locals, or Watch, inspecting the Customer object at index... because you are trying to perform an operation on a variable that has no definition In this particular example, LastName is null, but we’re still referencing LastName by calling the Trim method This is illogical because there is not a string to trim; the string variable is set to null Chapter 6: Debugging with Visual Studio You want the NullReferenceException to be raised because it protects you from performing... lastName); customerFound = true; } VB: Dim firstName As String = String.Empty If (cust.FirstName IsNot Nothing) Then firstName = cust.FirstName.Trim() End If Dim lastName As String Chapter 6: Debugging with Visual Studio If cust.LastName Is Nothing Then lastName = "" Else lastName = cust.LastName.Trim() End If If (searchName = firstName) Then Console.WriteLine( "Found: {0} {1}", cust.FirstName, cust.LastName)... Press F11 to step into the GetCustomers method VS will navigate to the first line of the GetCustomer method 6 Press F10 twice to see what values are being returned This example is so simple that you can visually see the data However, in real scenarios, you will probably be running code that makes the query to a database, or other data source, and might prepare that data in a form digestible by any potential... firstName variable This example makes it very easy to find the null value because it occurred on the line where VS paused In more challenging situations, you could be passing an object to a method in a third-party library where you don’t have the code and VS will pause on the line with the method call In that case, you have to inspect the values being passed to the method to see if any are null Once you’ve... navigate through your application, stepping into and out of methods and changing the executable location of your application You can also open several windows and inspect the state of your application In particular, you learned how to use the Debug History window that lets you see the state of an application at various stages of a debugging session In the next chapter, we migrate from a pure focus of working . will pause on a NullReferenceException when running 176 Microsoft Visual Studio 201 0: A Beginner’s Guide the program. In this particular example, VS pauses on the line that cleans LastName properties,. will have more properties. Notice that both properties are type string. 168 Microsoft Visual Studio 201 0: A Beginner’s Guide The CustomerRepository Class In this program, we create a class. custRep.GetCustomers(); var searchName = "Jean"; bool customerFound = false; 170 Microsoft Visual Studio 201 0: A Beginner’s Guide foreach (var cust in customers) { // 1. First Bug if (searchName

Ngày đăng: 04/07/2014, 03:20