Although ArrayLists and HashTables aren’t serializable in XML format, there will be occasions when you want to serialize data stored in collections of these two types (and perhaps other types of nonserializable collections). I singled out ArrayLists and HashTables because they’re the most common collections in Windows programming. Because the only collection that XML serialization classes can serialize is the array, it’s possible to serialize any collection by converting it to an array. It’s trivial to export the elements of an ArrayList to an array and then serialize the array. Of course, the array should contain elements of the same type, which must appear in the array’s declaration. Let’s consider an ArrayList of Book objects: the BooksList collection. You can move the elements of the ArrayList to an array of Book objects with a few statements like the following:
Dim BooksArray(BooksList.Count - 1) As Book Dim BK As Book, i As Integer For Each BK In BooksList BooksArray(i) = BK i += 1 Next
Having populated the BooksArray array with the collection of Book objects, you can serialize them into XML with the techniques discussed already. You can also export the ArrayList’s data to an array by using the method ToArray. The ArrayList’s elements will be exported to an array of the appropriate type. The reverse process will be used to deserialize the collection: First, you deserialize the data into an array, and then you move the array’s elements into the ArrayList:
' Statements to deserialize the BooksArray array Dim i As Integer For i = 0 To BooksArray.GetLength(0) - 1 BooksList.Add BooksArray(i) Next
Serializing HashTables might take a few more statements because it involves keys, not just data. Usually, each element’s key is one of the custom object’s properties. For Book objects, the most likely candidate for a key is the book’s ISBN. In this case, you just export all the objects from the HashTable into an ArrayList and proceed as explained already. If the collection’s key, however, isn’t a property of the custom object, you must create a new class that has the exact same structure as the Book class and an additional property for the key.
Public Class KeyBook Public Book As Book Public Key As String End Class
Couldn’t I take advantage of inheritance and derive the KeyBook class from the Book class? The answer is no, because the Book class can’t be cast into a derived class. In other words, you can cast KeyBook objects to Book objects but not the opposite. That’s why I had to create a new class with the custom type and a field for the key. (I’m not using a property procedure for the Key property because no application will ever access this member, except for the code that serializes/deserializes the collection.) The following statements extract the Book objects from the HashTable, convert them to KeyBook objects, and store them into the BooksArray array:
Dim BooksArray(HT.Count - 1) As KeyBook Dim bkey As Integer, i As Integer = 0 Dim KeyBook As New KeyBook For Each bkey In HT.Keys KeyBook.Book = HT(bkey) KeyBook.Key = bkey BooksArray(i) = KeyBook i += 1 Next
Serializing Generic Collections
As you’ll recall from Chapter, ‘‘Storing Data in Collections,”, there are several collections that belong to the Collections.Generic namespace, and they’re typed collections. The drawback of these collections is that they can be used to store objects of the same type — but in most applications this is an advantage, not a drawback. Typical collections contain objects of the same type, and you should use generic collections whenever possible.
Unlike the general collections, such as ArrayLists and HashTables, the generic collections are typed and can be serialized, because the compiler knows the type of objects stored in them. The List collection, for example, is the typed equivalent of the ArrayList collection. Although the ArrayList collection can’t be serialized with the XmlSerializer class, the List collection can be serialized with the same class. When you create a new instance of the XmlSerializer class, you pass the type of the object you intend to serialize as an argument:
Dim Persons As New System.Collections.Generic.List(Of Person) Dim XMLSRLZR As New XmlSerializer(Persons.GetType)
The compiler knows that the collection will be used to store objects of the Person type, and it can generate the appropriate XML structure. The statements for serializing and deserializing the collection are identical to the ones you’d use to serialize any other object:
' To serialize a typed collection: Dim strmWriter As New IO.StreamWriter(file_path) XMLSRLZR.Serialize(strmWriter, Persons) ' To deserialize a typed collection: Dim Rstrm As New IO.FileStream(file_path, IO.FileMode.Open) newPersons = CType(XMLSRLZR.Deserialize(Rstrm), _ System.Collections.Generic.List(Of Person))