Working with New Abstract Data Types in Visual Basic .NET
A revised Collection class similar to the VB6 Collection is defined in the Microsoft.VisualBasic namespace. Visual Basic .NET has added several new Abstract Data Types (ADTs) to ultimately replace the Collection class. The names of the new classes were enumerated in Chapter 2, including an example of using the Stack class. The subsections that follow demonstrate ArrayList, HashTable, SortedList, and Queue.
Members of ArrayList
The ArrayList class is a designed replacement for an unadorned array. Although arrays in Visual Basic .NET are classes, they are designed to work similarly to VB6 arrays. This means you have to resize the arrays and preserve elements manually, which is likely to yield code that is littered with ReDim statements.
Dynamic array sizing is semantical behavior that belongs to an array. In an object-oriented programming language, you would expect that such behavior is defined as part of an array class. Combining storage and capacity management in a single class is what ArrayList has to offer. You will find ArrayList easier to use than a System.Array or the VB6-style collection.
Table 3.1 lists the members of ArrayList.
Table 3.1 ArrayList Members
Name |
Description |
Shared Method |
|
Adapter |
Wraps an ArrayList around an object that implements IList |
FixedSize |
Returns a fixed-size wrapper, allowing elements to be modified but not added or removed |
ReadOnly |
Returns a read-only wrapper around an ArrayList |
Repeat |
Returns an ArrayList containing multiple copies of the argument value |
Synchronized |
Returns a thread-safe list wrapper |
Instance Property |
|
Capacity |
Used to get or change the capacity of an ArrayList |
Count |
Returns number of elements in the list; capacity may be greater than or equal to count |
IsFixedSize |
Returns a Boolean indicating whether or not the ArrayList has a fixed size |
IsReadOnly |
Returns a Boolean indicating whether or not the ArrayList is read-only |
IsSynchronized |
Returns a Boolean indicating whether or not access to the ArrayList is synchronized |
Item |
Used to index elements of the ArrayList |
SyncRoot |
Returns an object used to synchronize ArrayList access |
Instance Method |
|
Add |
Appends an element to the ArrayList, increasing the capacity if necessary |
AddRange |
Appends elements from an ICollection |
BinarySearch |
Searches for element using binary algorithm |
Clear |
Removes all elements |
Clone |
Performs shallow copy of all elements |
Contains |
Returns a Boolean indicating whether or not the element is in the ArrayList |
CopyTo |
Copies all or part of the ArrayList to a one-dimensional System.Array |
Equals |
Determines whether the argument array references the calling array |
GetEnumerator |
Returns ArrayList enumerator |
GetHashCode |
Hashing function inherited from Object |
GetRange |
Copies range of elements to a new ArrayList |
GetType |
Returns metaclass of ArrayList; inherited from Object |
IndexOf |
Returns the index of a particular element of the array list |
Insert |
Inserts an element into the list at specified index |
InsertRange |
Inserts a range of elements at specified index |
LastIndexOf |
Returns the index of the last occurrence of object |
Remove |
Removes the first instance of argument object |
RemoveAt |
Removes element at specified index |
RemoveRange |
Removes a range of elements at specified index |
Reverse |
Sorts the array in reverse order |
SetRange |
Copies range of elements over the elements in the ArrayList |
Sort |
Reorders the data in ascending order |
ToArray |
Copies elements to System.Array |
ToString |
Returns name of object |
TrimToSize |
Sets capacity to number of elements |
The next section demonstrates some of the characteristics of ArrayList.
Using ArrayList
The biggest benefit of ArrayList over System.Array is that ArrayList has dynamic capacity management built in. When you use System.Array, you have to make sure there is enough room for an element. If not, you have to add capacity to the array with ReDim. On the other hand, if you use the ArrayList Add, AddRange, Insert, or InsertRange methods, the capacity is adjusted as needed.
ArrayList has significant advantages over VB6 arrays but fewer advantages over Visual Basic .NET System.Array; however, capacity management is enough of a reason to prefer ArrayList over System.Array. Many of the methods in ArrayList are similar to methods in Array (see "Using Array Methods"); therefore, we will not repeat examples of those methods here. Capacity management and adding and managing a range of elements are additional features offered in ArrayList. Let's take a look at examples of using these behaviors. Listing 3.4 demonstrates behaviors of ArrayList that are not found in System.Array.
Listing 3.4 Behaviors of ArrayList not found in System.Array.
1: Sub DemoSetRange() 2: 3: Dim MyArray As New ArrayList() 4: 5: Dim Array1() As Integer = {0, 1, 2, 3, 4, 5} 6: 7: MyArray.InsertRange(0, Array1) 8: 9: Dim I As Integer 10: 11: For I = 0 To MyArray.Count 12: Debug.WriteLine(MyArray(I)) 13: Next 14: 15: Debug.WriteLine("Contains 3? " & MyArray.Contains(3)) 16: 17: End Sub
The example declares an ArrayList named MyArray using one of three possible constructors. The constructor on line 3 takes no parameters. Line 5 allocates a System.Array and initializes the members to the integers 0 through 5. Line 7 demonstrates ArrayList.InsertRange. InsertRange takes a start index and an ICollection object. System.Array implements the ICollection interface, so System.Array is a suitable argument for InsertRange. In fact, any class that implements ICollection (HashTable, Stack, Queue, and SortedList are other examples) is a suitable argument for InsertRange. Lines 11 through 13 demonstrate that elements of an ArrayList can be accessed as if it were a simple array. (Of course you can use the new Enumerator behavior that you saw in Listing 3.2, as well.)
Line 15 demonstrates the Contains method. Contains takes an object, which can be a literal integer like 3, and returns a Boolean indicating whether or not the object is in the ArrayList. In the example, Option Strict is On so the Boolean returned by Contains is printed using the ToString method of the Boolean type.
HashTable
Hash tables use key and value pairs. The key is processed through a hashing function that is designed to generate a unique value that is then used as an index into the hash table to the location containing the value. Hash tables strike a balance between resource usage and speed.
Instead of probing each element for equality to determine whether objects are equal, simply processing the key provides an index to the location that contains the associated value. There is a significant amount of research on hash tables, hashing functions, and key-collision avoidance. (You may have studied some of them in college if you were a computer science major, but the .NET Framework provides a HashTable implemented for you.)
The System.Collections.HashTable class implements a hash table available for you to use. HashTable works externally much like a data dictionary. Provide a unique key and an associated value, and the HashTable takes care of the rest.
Suppose you were storing personnel records in memory for quick access. You might key each record on the Social Security number, and the value would be the personnel record. (For the demonstration, we will simply store a person's name to represent the personnel record.)
Listing 3.5 declares a new instance of a hash table and adds some unique elements to the hash table keyed on pseudo-Social Security numbers. The values stored in the hash table represent the data associated with the keys. (The key is the first argument and the value is the second argument of the Add method.)
Listing 3.5 Storing items in a hash table.
1: Sub DemoHashTable() 2: Dim Hash As New Hashtable() 3: Hash.Add("555-55-5555", "Frank Arndt") 4: Hash.Add("555-55-5556", "Mary Bonnici") 5: Hash.Add("555-55-5557", "Paul Kimmel") 6: 7: Dim Enumerator As IDictionaryEnumerator = Hash.GetEnumerator 8: 9: While (Enumerator.MoveNext()) 10: Debug.WriteLine(Enumerator.Key & "=" & _ 11: Enumerator.Value) 12: End While 13: 14: End Sub
TIP
Enumerator objects are read-only. To modify elements of a collection like a HashTable, you can use a For Next loop, indexing the elements of the collection directly.
HashTable uses an IDictionaryEnumerator object to iterate over elements. Line 7 declares an enumerator and lines 9 through 12 iterate over each element displaying the key and value pairs. (.Key and .Value were not defined in the IEnumerator interface; they were added in the IDictionaryEnumerator.)
SortedList
The SortedList ADT is based on the dictionary interface. Recall from the last section that a dictionary is a collection of key (or name) and value pairs. SortedList maintains two internal arrays. One keeps track of keys and the second keeps track of values. As with a hash table, the key values of a sorted list must be unique.
SortedList has methods similar to ArrayList, in addition to the key and value pairs introduced with HashTable. SortedList is defined in the System.Collections namespace. For more information on SortedList, look in the MSDN help files.
Queue
Queue data structures are also referred to as First In First Out (FIFO) data structures. Think of a queue as a line. There is a first in line, a last in line, and everything in between.
Just as Stacks have a language for adding elements to the collectionPush and Popto denote adding and removing elements to a Stack, Queue uses the notion of enqueuing and dequeuing. All of the collection-based ADTs work with Objects; hence to enqueue means to add an Object to the queue and to dequeue means to remove an object from the queue.
Queues are a natural choice when you want the first item put into a collection to be the first item out. Listing 3.6 demonstrates basic queue behavior.
Listing 3.6 Basic queue behavior.
1: Sub DemoQueue() 2: 3: Dim Q As New Queue() 4: Q.Enqueue("One") 5: Q.Enqueue("Two") 6: 7: While (Q.Count > 0) 8: Debug.WriteLine(Q.Dequeue) 9: End While 10: 11: End Sub
The output from Listing 3.6 is One and Two. The elements are dequeued in exactly the same order in which they were enqueued.
Queues implement several of the same COM interfaces as other ADTs defined in the System.Collections namespace, like ICollection, IEnumerable, and ICloneable. For this reason queues have many of the same operations by name as other ADTs.
Assessing the ADTs
For general purpose in-memory storage, ArrayList will suffice. For key and value pairs, use HashTable or SortedList. If you want objects stored and retrieved in the same order, use Queue, and if you want the last element put into a collection to be the first one out, use Stack. The fundamental behaviors of the collection classes are identical. The semantic operations are consistent with the type of data structure.