Visual Basic 2005 with .NET 3.0 Programmer's Reference

Visual Basic programs allocate variables from two pools of memory called the stack and the heap. It takes memory for value types (such as integers and dates) from the stack.

Space for reference types comes from the heap. More than one reference can point to the same chunk of memory allocated on the heap. That makes garbage collection and other heap-management issues more complex than using the stack, so using the heap is generally slower than using the stack.

Because structures are value types and classes are reference types, structures are allocated on the stack and class objects are allocated from the heap. That makes structures faster than classes. The exact difference for a particular program depends on the application.

Note that arrays are themselves reference types, so all arrays are allocated from the heap whether they contain structures or references to class objects. The memory for an array of structures is allocated all at once, however, so there is still some benefit to using structures. All the memory in an array of structures is contiguous, so the program can access its elements more quickly than it would if the memory were scattered throughout the heap.

Object Assignment

When you assign one reference type variable to another, you make a new reference to an existing object. When you are finished, the two variables point to the same object. If you change the object’s fields using one variable, the fields shown by the other are also changed.

On the other hand, if you set one value type variable equal to another, Visual Basic copies the data from one to the other. If you change the fields in one object, the fields in the other remain unchanged. Figure 16-3 illustrates the difference.

Figure 16-3: Assigning one class reference to another makes them both point to the same object. Assigning one structure variable to another makes a new copy of the data.

To see the difference in code, consider the following declarations. The CPerson class and the SPerson structure are the same, except that one is a class and the other is a structure.

Public Class CPerson Public FirstName As String Public LastName As String End Class Public Structure SPerson Public FirstName As String Public LastName As String End Structure

Now consider the following code. The program creates two CPerson references and initializes the first to a new CPerson object. It sets cperson1.FirstName to Alice and then sets cperson2 = cperson1. The code then sets cperson2.FirstName to Ben. Because these are reference variables, they both point to the same object, so this changes the FirstName value of the underlying object and the message box displays the text “Ben, Ben.” Next the program repeats these steps using the SPerson structure instead of the CPerson class. When the code sets sperson2 = sperson1, Visual Basic copies the values from sperson1 into sperson2. At that point, both objects have a FirstName value of Alice. The code then sets sperson2.FirstName to Ben. Because the two structure variables refer to different objects, this does not affect sperson1 and the message box displays the text “Alice, Ben.”

Dim cperson1 As New CPerson Dim cperson2 As CPerson cperson1.FirstName = "Alice" cperson2 = cperson1 cperson2.FirstName = "Ben" MessageBox.Show(cperson1.FirstName & ", " & cperson2.FirstName) Dim sperson1 As New SPerson Dim sperson2 As SPerson sperson1.FirstName = "Alice" sperson2 = sperson1 sperson2.FirstName = "Ben" MessageBox.Show(sperson1.FirstName & ", " & sperson2.FirstName)

Parameter Passing

When you pass a parameter to a function or subroutine, you can pass it by reference using the ByRef keyword, or by value using the ByVal keyword. If you pass a parameter by reference, any changes that the routine makes are reflected in the original parameter passed into the routine.

For example, consider the following code. Subroutine TestByRef creates an integer named i and sets its value to 1. It then calls subroutine PassByVal. That routine declares its parameter with the ByVal keyword, so i is passed by value. PassByVal multiplies its parameter by 2 and ends. Because the parameter was declared ByVal, the original variable i is unchanged, so the message box displays the value 1. Next the program calls subroutine PassByRef, passing it the variable i. Subroutine PassByRef declares its parameter with the ByRef keyword, so a reference to the variable is passed into the routine. PassByRef doubles its parameter and ends. Because the parameter is declared with the ByRef keyword, the value of variable i is modified so the message box displays the value 2.

Public Sub TestByRef() Dim i As Integer = 1 PassByVal(i) MessageBox.Show(i.ToString) ' i = 1. PassByRef(i) MessageBox.Show(i.ToString) ' i = 2. End Sub Public Sub PassByVal(ByVal the_value As Integer) the_value *= 2 End Sub Public Sub PassByRef(ByRef the_value As Integer) the_value *= 2 End Sub

When you work with class references and structures, you must think a bit harder about how ByRef and ByVal work. There are four possible combinations: reference ByVal, structure ByVal, reference ByRef, and structure ByRef.

If you pass a class reference to a routine by value, the routine receives a copy of the reference. If it changes the reference (perhaps making it point to a new object), the original reference passed into the routine remains unchanged. It still points to the same object it did when it was passed to the routine. However, the routine can change the values in the object to which the reference points. If the reference points to a Person object, the routine can change the object’s FirstName, LastName, and other fields. It cannot change the reference itself to make it point to a different Person object, but it can change the object’s data.

On the other hand, suppose that you pass a structure into a routine by value. In that case, the routine receives a copy of the entire structure. The routine can change the values contained in its copy of the structure, but the original structure’s values remain unchanged. It cannot change the original structure’s fields the way it could if the parameter were a reference type.

If you pass a class reference variable by reference, then the routine can not only modify the values in the object to which the reference points but can also change the object to which it points. The routine could use the New keyword to make the variable point to a completely new object.

If you pass a structure by reference, the routine receives a pointer to the structure’s data. If it changes the structure’s data, the fields in the original variable passed into the routine are modified.

In addition to these differences in behavior, passing class references and structures by reference or by value can make differences in performance. When you pass a pointer to data, Visual Basic only needs to send the routine a 4-byte value. If you pass a structure into a routine by value, Visual Basic must duplicate the entire structure, so the routine can use its own copy. If the structure is very large, that may take a little extra time.

Boxing and Unboxing

Visual Basic allows a program to treat any variable as an object. For example, a collection class stores objects. If you add a simple value type such as an Integer to a collection, Visual Basic wraps the Integer in an object and adds that object to the collection.

The process of wrapping the Integer in an object is called boxing. Later, if you need to use the Integer as a value type again, the program unboxes it. Because structures are value types, the program must box and unbox them whenever it treats them as objects, and that adds some extra overhead.

Some operations that require boxing and possibly unboxing include assigning a structure to an Object variable, passing a structure to a routine that takes an Object as a parameter, or adding a structure to a collection class. Note that this last operation includes adding a structure to a collection used by a control or other object. For example, adding a structure to a ListBox control’s Items collection requires boxing.

Note that arrays are themselves reference types, so treating an array as an object doesn’t require boxing.

Категории