Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 92 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
92
Dung lượng
1,34 MB
Nội dung
Chapter 10: Debugging and Error Handling 335 12. Add the following two properties to the end of the Computer class: Public ReadOnly Property FreeMemory() As String Get ‘Using the My namespace Return Format(( _ My.Computer.Info.AvailablePhysicalMemory.ToString \ 1024), _ “#,###,##0”) & “ K” End Get End Property Public ReadOnly Property TotalMemory() As String Get ‘Using the My namespace Return Format(( _ My.Computer.Info.TotalPhysicalMemory.ToString \ 1024), _ “#,###,##0”) & “ K” End Get End Property 13. Switch to the code for the Debug form and add the following highlighted Imports statement: Imports System.Collections.Generic Public Class Debug 14. You need to add a few private variable declarations next. Add the following code: Public Class Debug ‘Using the Generics class Private objStringValues As New Generics(Of String) Private objIntegerValues As New Generics(Of Integer) ‘Using the List < T > class Private objCustomerList As New List(Of Customer) 15. Add the following ListCustomer procedure to add customers to the list box on your form: Private Sub ListCustomer(ByVal customerToList As Customer) lstData.Items.Add(customerToList.CustomerID & _ “ - “ & customerToList.CustomerName) End Sub 16. Next, you need to add the rest of the code to the Start button Click event handler. Select btnStart in the Class Name combo box at the top of the Code Editor and then select the Click event in the Method Name combo box. Add the following highlighted code to the Click event handler: Private Sub btnStart_Click(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles btnStart.Click c10.indd 335c10.indd 335 4/1/08 6:26:08 PM4/1/08 6:26:08 PM Chapter 10: Debugging and Error Handling 336 ‘Declare variables Dim strData As String lstData.Items.Add(“String variable data:”) If strData.Length > 0 Then lstData.Items.Add(strData) End If ‘Add an empty string to the ListBox lstData.Items.Add(String.Empty) ‘Demonstrates the use of the List < T > class lstData.Items.Add(“Customers in the Customer Class:”) objCustomerList.Add(New Customer(1001, “Henry For”)) objCustomerList.Add(New Customer(1002, “Orville Wright”)) For Each objCustomer As Customer In objCustomerList ListCustomer(objCustomer) Next ‘Add an empty string to the ListBox lstData.Items.Add(String.Empty) ‘Demonstrates the use of Generics lstData.Items.Add(“Generics Class Key/Value Pairs using String Values:”) objStringValues.Add(“1001”, “Henry Ford”) lstData.Items.Add(objStringValues.Key(0) & “ = “ & _ objStringValues.Value(0)) ‘Add an empty string to the ListBox lstData.Items.Add(String.Empty) ‘Demonstrates the use of Generics lstData.Items.Add(“Generics Class Key/Value Pairs using Integer Values:”) objIntegerValues.Add(“Henry Ford”, 1001) lstData.Items.Add(objIntegerValues.Key(0) & “ = “ & _ objIntegerValues.Value(0)) ‘Add an empty string to the ListBox lstData.Items.Add(String.Empty) ‘Demonstrates the use of the Using statement ‘Allows acquisition, usage and disposal of the resource lstData.Items.Add(“Computer Class Properties:”) Using objMemory As New Computer lstData.Items.Add(“FreeMemory = “ & objMemory.FreeMemory) lstData.Items.Add(“TotalMemory = “ & objMemory.TotalMemory) End Using ‘Add an empty string to the ListBox lstData.Items.Add(String.Empty) ‘Demonstrates the use of the Continue statement Dim strPassword As String = “POpPassword” Dim strLowerCaseLetters As String = String.Empty ‘Extract lowercase characters from string c10.indd 336c10.indd 336 4/1/08 6:26:08 PM4/1/08 6:26:08 PM Chapter 10: Debugging and Error Handling 337 For intIndex As Integer = 0 To strPassword.Length - 1 ‘Demonstrates the use of the Continue statement ‘If no uppercase character is found, continue the loop If Not strPassword.Substring(intIndex, 1) Like “[a-z]” Then ‘No upper case character found, continue loop Continue For End If ‘Lowercase character found, save it strLowerCaseLetters & = strPassword.Substring(intIndex, 1) Next ‘Display lowercase characters lstData.Items.Add(“Password lower case characters:”) lstData.Items.Add(strLowerCaseLetters) End Sub 17. Before examining how the code works, hover your mouse over the Error List tab at the bottom of the IDE so that the Error List window appears as shown in Figure 10 - 7 . If the Error List tab is not visible, select View Error List from the menu bar. You have one warning about a potential error in your code. The line in question causes an error when you run your project; however, this is deliberate and is intended to demonstrate some of the debugging capabilities of Visual Studio 2008. You can ignore this warning for now, because you ’ ll be correcting it shortly. Figure 10-7 18. Save your project by clicking the Save All button on the toolbar. How It Works After building the user interface for the Debugging project, you add the Customer class. This class is also straightforward and contains two private variables, a constructor, and two properties. The two variables in the Customer class are declared as Private, which means that these variables are accessible only to the procedures in the class: Public Class Customer Private intCustomerID As Integer Private strName As String The constructor for this class — a method called whenever a new object of this class is to be created — is defined as a Public procedure with a procedure name of New . All constructors for classes in the .NET Framework must be declared with a procedure name of New . c10.indd 337c10.indd 337 4/1/08 6:26:09 PM4/1/08 6:26:09 PM Chapter 10: Debugging and Error Handling 338 This constructor accepts two input parameters: customerID and name . The parameters are used to set the values in the private variables defined for this class: Public Sub New(ByVal customerID As Integer, ByVal name As String) intCustomerID = customerID strName = name End Sub Two properties are defined: CustomerID and CustomerName . These are read - only properties, meaning that the consumer of this class can use these properties only to read the Customer ID and customer name; consumers cannot change them: Public ReadOnly Property CustomerID() As Integer Get Return intCustomerID End Get End Property Public Property CustomerName() As String Get Return strName End Get End Property End Class The next class that you add to the Debugging project is the Generics class. This class will be used to demonstrate the use of Generics in Visual Basic 2008. The Collections class in the .NET Framework allows you to store data in the collection in a key/ value pair. The key is always a string value that identifies the value, also known as an item . The item is defined as an object, which allows you to use the Collection class to store any data type that you want in the item. So, for example, you can use the Collection class to store Integer values or you can use it to store String values. No type checking is performed. This lack of specificity can lead to performance problems as well as run - time problems. Suppose you intend to use the Collection class to store Integer values. If (through poor coding practices) you allowed a String value to be added to the collection, you would not receive a run - time error when adding the item, but you could receive one when you tried to access the item. The performance problems that you will encounter are the conversion of the data going into the collection and the data coming out of the collection. When you add an item to the collection, the data must be converted from its native data type to an Object data type, since that is how the Item property is defined. Likewise, when you retrieve an item from the collection, the item must be converted from an Object data type to the data type that you are using. In Chapter 5 , when working with ArrayList s (which are a kind of collection), you solved the problem of being able to store items of the wrong type by creating a strongly typed collection class. This did not solve the performance problem. Both problems are solved through Generics and through the introduction of type constraints . A type constraint is specified on a class such as Collection by using the Of keyword followed by a list of type name placeholders that are replaced by actual type names when an object of the class is created. This provides type safety by not allowing you to add an item that is not of the same data type that was defined for the class. It also improves performance because the item does not have to be converted to and from the Object data type. The data type for c10.indd 338c10.indd 338 4/1/08 6:26:09 PM4/1/08 6:26:09 PM Chapter 10: Debugging and Error Handling 339 the item is defined using the data type that was defined for the class. You ’ ll see how all of this works in more detail as you explore the rest of the code and as you go through the debugging process. After adding the Generics class, you modify the class by adding a type constraint using the Of keyword and defining a type list, which in this case contains only one type. This type name is a placeholder that will be used throughout the class to represent the data type that this class is working with. The actual data type is defined when an object of the class is created, as you ’ ll see later in your code: Public Class Generics(Of elementType) End Class You add two private variables to this class, with both of these variables being defined as an array. The first variable is a defined as a String data type, while the second variable is defined as a generic data type, which is set when an object of the class is created. Note that you have used the type name elementType , which was defined at the class level. This type name is replaced automatically by the data type that is used to create the Generics object. Public Class Generics(Of elementType) ‘This class provides a demonstration of Generics ‘Declare Private variables Private strKey() As String Private elmValue() As elementType The Add method allows you to add items to your collection. This method accepts two parameters; one for the key and the other for the value, making a key/value pair. The key parameter is always a string value, and the value parameter is defined using the data type that is used when a Generics collection is created. The first thing that you want to do in this procedure is to see whether the variable arrays have been initialized. You do this by using the IsNot operator and comparing the strKey array to a value of Nothing . If the array is not equal to a value of Nothing , the array has already been initialized, and you simply need to increment the array dimension by one. This is done by first getting the current upper bounds of the array and then adding 1 to it. If the variable arrays have not been initialized, you need to initialize them using the ReDim statement as shown in the Else statement in the code that follows. After the arrays have been expanded or initialized, you add the key and value to the arrays: Public Sub Add(ByVal key As String, ByVal value As elementType) ‘Check to see if the objects have been initialized If strKey IsNot Nothing Then ‘Objects have been initialized ReDim Preserve strKey(strKey.GetUpperBound(0) + 1) ReDim Preserve elmValue(elmValue.GetUpperBound(0) + 1) c10.indd 339c10.indd 339 4/1/08 6:26:10 PM4/1/08 6:26:10 PM Chapter 10: Debugging and Error Handling 340 Else ‘Initialize the objects ReDim strKey(0) ReDim elmValue(0) End If ‘Set the values strKey(strKey.GetUpperBound(0)) = key elmValue(elmValue.GetUpperBound(0)) = value End Sub You add two read - only properties to this class to return the key and the value for a key/value pair. Notice that the Value property is defined to return the data type that will be used when a Generics object is created. Public ReadOnly Property Key(ByVal Index As Integer) As String Get Return strKey(Index) End Get End Property Public ReadOnly Property Value(ByVal Index As Integer) As elementType Get Return elmValue(Index) End Get End Property End Class The final class that you added was the Computer class. This class implements the IDisposable interface. An interface in this sense is a set of methods and properties common to all classes that implement it. In this case, the IDisposable interface contains methods for releasing memory resources when an object of the class is disposed of. Methods that use this class should call the Dispose method when they are through with a Computer object. To implement the interface, you add the Implements statement and specify the IDisposable interface. When you press the Enter key, Visual Studio 2008 adds the code from the IDisposable interface to your class, as shown in the following code: Public Class Computer Implements IDisposable Private disposedValue As Boolean = False ‘ To detect redundant calls ‘ IDisposable Protected Overridable Sub Dispose(ByVal disposing As Boolean) If Not Me.disposedValue Then If disposing Then ‘ TODO: free other state (managed objects). End If ‘ TODO: free your own state (unmanaged objects). ‘ TODO: set large fields to null. End If c10.indd 340c10.indd 340 4/1/08 6:26:10 PM4/1/08 6:26:10 PM Chapter 10: Debugging and Error Handling 341 Me.disposedValue = True End Sub #Region “ IDisposable Support “ ‘ This code added by Visual Basic to correctly implement ‘ the disposable pattern. Public Sub Dispose() Implements IDisposable.Dispose ‘ Do not change this code. Put cleanup code in ‘ Dispose(ByVal disposing As Boolean) above. Dispose(True) GC.SuppressFinalize(Me) End Sub #End Region End Class You add two read - only properties to this class; FreeMemory and TotalMemory . These properties return the available memory on your computer as well as the total amount of memory on your computer. These properties use the My.Computer.Info namespace to access the amount of available memory and the total amount of memory. The AvailablePhysicalMemory and TotalPhysicalMemory properties of the My.Computer.Info namespace return the available and total memory in bytes. However, we as users are used to seeing these numbers in kilobytes. Therefore you convert the number of bytes into kilobytes and then have that number formatted using commas. Remember that there are 1024 bytes to a kilobyte, 1024 kilobytes to a megabyte, and so on. The number that you pass to the Format function will be in kilobytes after you divide the number of bytes by 1024. You then add a space to the formatted number and then the letter K indicating that the available and total memory figures are in kilobytes: Public ReadOnly Property FreeMemory() As String Get ‘Using the My namespace Return Format(( _ My.Computer.Info.AvailablePhysicalMemory.ToString \ 1024), _ “#,###,##0”) & “ K” End Get End Property Public ReadOnly Property TotalMemory() As String Get ‘Using the My namespace Return Format(( _ My.Computer.Info.TotalPhysicalMemory.ToString \ 1024), _ “#,###,##0”) & “ K” End Get End Property c10.indd 341c10.indd 341 4/1/08 6:26:10 PM4/1/08 6:26:10 PM Chapter 10: Debugging and Error Handling 342 You add code to the Debug form class next. This class uses a class List < T > , which is a generic list class. You ’ ll be using this class to hold a list of Customer objects created from your Customer class. The List < T > class uses a dynamically sized array to hold the objects of the type that you specify: You need to import the System.Collections.Generic namespace in order to access the List < T > class. You accomplish that requirement by using an Imports statement. Imports System.Collections.Generic Next you define three private objects at the class level; these objects are available to all procedures in this class. The first two objects use your Generics class. Remember that the Generics class used the Of keyword to define a type list. In the declaration of your objects, you use similar Of clauses to specify that the Generics class should be using a String data type in the type list for the first object and an Integer data type for the second object. The data type specified here will be applied throughout the Generics class. The last object that you define here is an object that holds an array of Customer objects created from your Customer class: ‘Using the Generics class Private objStringValues As New Generics(Of String) Private objIntegerValues As New Generics(Of Integer) ‘Using the List < T > class Private objCustomerList As New List(Of Customer) The ListCustomer procedure simply accepts a Customer object as input and adds the Customer ID and Customer Name to the list box on your form: Private Sub ListCustomer(ByVal customerToList As Customer) lstData.Items.Add(customerToList.CustomerID & _ “ - “ & customerToList.CustomerName) End Sub The Click event handler for the Start button contains the rest of the code for your project. You start this procedure by declaring a local String variable that will be used to demonstrate checking to see whether a variable has been initialized. The code following the variable declaration checks the length of the variable and then adds the contents of the variable to the list box on the form. Private Sub btnStart_Click(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles btnStart.Click ‘Declare variables Dim strData As String lstData.Items.Add(“String variable data:”) If strData.Length > 0 Then lstData.Items.Add(strData) End If c10.indd 342c10.indd 342 4/1/08 6:26:10 PM4/1/08 6:26:10 PM Chapter 10: Debugging and Error Handling 343 Since you will be writing the various results of your processing to the list box on your form, you ’ ll want to add a blank entry to the list box to separate your results for aesthetic reasons, which is what the next line of code does. Here you simply use the Empty method of the String class to return an empty string to be added to the list box: ‘Add an empty string to the ListBox lstData.Items.Add(String.Empty) This next section of code demonstrates the use of the List < T > class, as the comment in the code indicates. You add two new Customer objects to the objCustomerList object and then display those customers in the list box. Using a For Each . . . Next loop to iterate through the collection of Customer objects, you add each customer to the list box by calling the ListCustomer function passing that function the Customer object: ‘Demonstrates the use of the List < T > class lstData.Items.Add(“Customers in the Customer Class:”) objCustomerList.Add(New Customer(1001, “Henry For”)) objCustomerList.Add(New Customer(1002, “Orville Wright”)) For Each objCustomer As Customer In objCustomerList ListCustomer(objCustomer) Next Again you add a blank entry to the list box and use the objects that were defined using your Generics class. The first object, objStringValues , uses the Generics class with a String data type, as the object name indicates. Remember that the Add method in this class accepts a key/value pair and that the key parameter is always a String value. The value parameter uses the data type that was used to initialize this class, which in this case is also a string. When you add a key/value pair to your objStringValues object, you want to display that data in the list box on your form. You do this by accessing the Key and Value properties in the Generics class from which this object was derived: ‘Add an empty string to the ListBox lstData.Items.Add(String.Empty) ‘Demonstrates the use of Generics lstData.Items.Add(“Generics Class Key/Value Pairs using String Values:”) objStringValues.Add(“1001”, “Henry Ford”) lstData.Items.Add(objStringValues.Key(0) & “ = “ & _ objStringValues.Value(0)) Again you add another blank line to the list box and then add a key/value pair that uses an Integer data type for the value parameter to the objIntegerValues object. Then you add that key/value pair to the list box: ‘Add an empty string to the ListBox lstData.Items.Add(String.Empty) ‘Demonstrates the use of Generics lstData.Items.Add(“Generics Class Key/Value Pairs using Integer Values:”) objIntegerValues.Add(“Henry Ford”, 1001) lstData.Items.Add(objIntegerValues.Key(0) & “ = “ & _ objIntegerValues.Value(0)) c10.indd 343c10.indd 343 4/1/08 6:26:11 PM4/1/08 6:26:11 PM Chapter 10: Debugging and Error Handling 344 After you add another blank line to the list box, you use a Using . . . End Using block to create a new object of the Computer class, add the free memory and total memory of your computer to the list box, and then dispose of the Computer class. When you use a class, you typically instantiate it using the New keyword as you did with your Generics class, use the class, and then dispose of the class by calling its Dispose method if it implements one. The problem with that scenario is that when an exception occurs, the resource may or may not be disposed of. Even if you implement the code using structure error handling, a topic I ’ ll discuss later in this chapter, you are not always guaranteed to be able to dispose of the class. The Using statement is an efficient means of acquiring a resource, using it, and then disposing of it, regardless of whether an exception occurs. There is one caveat to this: the class that you use in a Using . . . End Using block must implement the IDisposable interface. This is why you added this interface to your Computer class. In the following code, the object name, objMemory , has not been defined anywhere except in the Using statement. The Using statement takes care of declaring this object for you and sets it to a new instance of the class that you specify, which in this case is the Computer class. Keep in mind that the object, objMemory , is local to the Using . . . End Using block and you can only reference it within this block. When the End Using statement is reached, the Common Language Runtime (CLR) automatically calls the Dispose method on the Computer class, thereby releasing its reference to it, and the Computer class executes any cleanup code that has been implemented in the Dispose method: ‘Add an empty string to the ListBox lstData.Items.Add(String.Empty) ‘Demonstrates the use of the Using statement ‘Allows acquisition, usage and disposal of the resource lstData.Items.Add(“Computer Class Properties:”) Using objMemory As New Computer lstData.Items.Add(“FreeMemory = “ & objMemory.FreeMemory) lstData.Items.Add(“TotalMemory = “ & objMemory.TotalMemory) End Using Once again you add another blank line to the list box, and then you get to the final bit of code in this procedure. In this section of code we wanted to demonstrate the use of the Continue statement. The Continue statement is an efficient means of immediately transferring control to the next iteration of a loop. Instead of coding a lot of If . . . Then statements in a loop, you can merely test to see whether a condition is what you want and if it is not, you can call the Continue statement to pass control to the next iteration of a Do , For , or While loop. Take a look at the code that you have here. First you declare a couple of variables and set their values. The first variable, strPassword , is declared and set to a password that contains upper - and lowercase letters. The second variable, strLowerCaseLetters , is declared and set to an empty string so that the variable is initialized. Next, you set up a For . . . Next loop to check each character in the strPassword variable. The If . . . Then statement uses the Like operator to compare a character in the password variable to a pattern of letters. If a match is found, the Like operator returns a value of True . However, you are using a negative comparison here, because you have included the Not keyword in the If . . . Then c10.indd 344c10.indd 344 4/1/08 6:26:11 PM4/1/08 6:26:11 PM [...]... declared Figure 10-22 355 c10.indd 355 4/1/08 6:26: 15 PM Chapter 10: Debugging and Error Handling 4 While you have the QuickWatch dialog box open, set an expression to be evaluated Add the expression intIndex = 1 in the Expression drop-down box Then click the Add Watch button to have this expression added to the Watch window Now close the QuickWatch dialog box by clicking the Close button 5 If you do not... Figure 10- 15 350 c10.indd 350 4/1/08 6:26:13 PM Chapter 10: Debugging and Error Handling Click the Run To Cursor icon on the toolbar The code between the breakpoint at the End If statement shown in Figure 10-14 and the line of code that calls the ListCustomer procedure, shown in Figure 10- 15, is executed Your project stops execution on the line of code on which you have your cursor Figure 10- 15 3 Click... which this object is derived as shown in Figure 10- 25 Figure 10- 25 5 Now click the Continue icon on the Debug toolbar until you encounter your second breakpoint 6 Now take a look at the Locals window, and you see a different set of objects and variables The one constant item in both procedures is Me, which is associated with the form 357 c10.indd 357 4/1/08 6:26:16 PM Chapter 10: Debugging and Error... and languages make object orientation (OO) a wonderfully easy-to-understand concept that brings massive benefits to software developers This is mainly because languages such as Visual Basic, C++, and, of course, Visual Basic 2008 and C# have matured to a point where they make creating objects and the programs that use them very easy indeed With these development tools, you will have no problem understanding... an unknown state Visual Studio 2008 provides structured error-handling statements that are common across all languages Structured error handling is a way to organize blocks of code in a structure that handles errors In this section you examine structured error handling and how it can be incorporated into your programs with very little effort Structured error handling in Visual Studio 2008 is incorporated... thoroughly testing your code The online documentation for most methods that you use in Visual Studio 2008 will have Exceptions sections that list and explain the possible exceptions that could occur by using the method Summar y This chapter covered some useful debugging tools that are built into the Visual Studio 2008 development environment You saw how easy it is to debug your programs as you stepped... variable to be displayed automatically in the Text Visualizer dialog box, which is a useful tool for displaying the data for string variables that contain a significant amount of data Clicking the down arrow provides you a drop-down list of options for viewing the contents of the variable and contains an option for Text Visualizer, XML Visualizer, and HTML Visualizer Figure 10-14 2 At this point, you’ll... An object that represents a bill that is produced ❑ Printer: An object that represents a hardware printer that can be used to print the bill When you write software in Visual Basic 2008, you are given a vast set of classes called the Microsoft NET Framework Classes These classes describe virtually everything about the computing environment that you’re trying to write software for Writing object-oriented... the Exception Assistant dialog box displays the type of exception that occurred in the title bar of the dialog box It also provides links to some basic troubleshooting tips and also a link at the bottom that provides the details of the exception 3 45 c10.indd 3 45 4/1/08 6:26:12 PM Chapter 10: Debugging and Error Handling Figure 10-8 3 Click the View Detail link in Exception Assistant dialog box to view... the program must be paused before a value can be changed) The text for a value that has just changed also turns red, making it easy to spot the variable or object that has just changed 356 c10.indd 356 4/1/08 6:26: 15 PM Chapter 10: Debugging and Error Handling The Locals window is great if you want a quick glance at everything that is going on in a function or procedure, but it is not very useful for . ListCustomer procedure as shown in Figure 10 - 15 . c10.indd 350 c10.indd 350 4/1/08 6:26:13 PM4/1/08 6:26:13 PM Chapter 10: Debugging and Error Handling 351 Click the Run To Cursor icon on the toolbar of your variables change without any intervention on your part. c10.indd 354 c10.indd 354 4/1/08 6:26: 15 PM4/1/08 6:26: 15 PM . options for viewing the contents of the variable and contains an option for Text Visualizer, XML Visualizer, and HTML Visualizer. ❑ Figure 10-14 2. At this point, you ’ ll want to test the debugging