Let’s start with binary serialization, which is implemented in the following namespace (you must import it into your application):
Imports System.Runtime.Serialization.Formatters.Binary
Code language: CSS (css)
This namespace isn’t loaded by default, and you must add a reference to the corresponding namespace. Right-click the project’s name in the Solution Explorer and choose Add Reference from the context menu. In the Add Reference dialog box that appears, select the same namespace as in the Imports statement shown earlier.
To use a SOAP serializer, add the appropriate reference and import the following namespace:
Imports System.Runtime.Serialization.Formatters.Soap
Code language: CSS (css)
After the appropriate namespace has been imported to the current project, you can serialize individual objects as well as collections of objects. Let’s start with single-object serialization.
Serializing Individual Objects
To serialize an object, you must call the Serialize method of the System.Runtime.Serialization.Formatters.Binary object. First, declare an object of this type with a statement like the following:
Dim BFormatter As New BinaryFormatter()
Code language: PHP (php)
The BinaryFormatter class persists objects in binary format. You can also persist objects in text format by using the SoapFormatter class. SoapFormatter persists the objects in XML format, which is quite verbose, and the corresponding files are considerably lengthier. To use the SoapFormatter class, declare a SoapFormatter variable with the following statement:
Dim SFormatter As Soap.SoapFormatter
Code language: CSS (css)
SOAP is a protocol for accessing objects over HTTP — in other words, it’s a protocol that allows the encoding of objects in text format. SOAP was designed to enable distributed computing over the Internet. SOAP uses text to transfer all kinds of objects, including images and audio, and therefore it’s not rejected by firewalls.
The methods of BinaryFormatter and SoapFormatter are equivalent, so I will use Binary Formatter in the examples of this section. To serialize an object, call the Serialize method of the appropriate formatter, whose syntax is the following, where stream is a variable that represents a stream and object is the object you want to serialize:
BFormatter.Serialize(stream, object)
Code language: CSS (css)
Because we want to persist our objects to disk files, the stream argument represents a stream to a file where the serialized data will be stored. The File object and its methods were discussed in detail in Chapter, ‘‘Accessing Folders and Files.” Here I will explain only briefly the statements we’ll use to store data to a disk file and read it back. The following statements create such a Stream object:
Dim saveFile As FileStream
saveFile = File.Create(”C:\Shapes.bin”)
Code language: PHP (php)
The saveFile variable represents the stream to a specific file on the disk, and the Create method of the same variable creates a stream to this file.
After you have set up the Stream and BinaryFormatter objects, you can call the Serialize method to serialize any object. To serialize a Rectangle object, for example, use the following statements:
Dim R As New Rectangle(0, 0, 100, 100)
BFormatter.Serialize(saveFile, R)
Code language: PHP (php)
Listing 12.1 serializes two Rectangle objects to the Shapes.bin file in the root folder. The file’s extension can be anything. Because the file is binary, I used the BIN extension.
Listing 12.1: Serializing Distinct Objects
Dim R1 As New Rectangle()
R1.X = 1
R1.Y = 1
R1.Size.Width = 10
R1.Size.Height = 20
Dim R2 As New Rectangle()
R2.X = 10
R2.Y = 10
R2.Size.Width = 100
R2.Size.Height = 200
Dim saveFile As FileStream
saveFile = File.Create("C:\SHAPES.BIN")
Dim formatter As BinaryFormatter
formatter = New BinaryFormatter()
formatter.Serialize(saveFile, R1)
formatter.Serialize(saveFile, R2)
saveFile.Close()
Code language: PHP (php)
Notice that the Serialize method serializes a single object at a time. To save the two rectangles, the code calls the Serialize method once for each rectangle. To serialize multiple objects with a single statement, you must create a collection, append all the objects to the collection, and then serialize the collection itself, as explained in the following section. If you serialize multiple objects of different types into the same stream, you can’t deserialize them unless you know the order in which the objects were serialized and deserialize them in the same order.
Deserializing Individual Objects
To deserialize a serialized object, you must create a new binary or SOAP formatter object and call its Deserialize method. Because the serialized data doesn’t contain any information about the original object, you can’t reconstruct the original object from the serialized data, unless you know the type of object that was serialized. Deserialization is always more difficult than serialization, and you have to know what you’re doing. Whereas the Serialize method will always serialize the object you pass as an argument, the Deserialize method won’t reconstruct the original object unless you know the type of the object you’re deserializing. The Shapes.bin file of Listing 12.1 in section “Serializing Individual Objects” contains the serialized versions of two Rectangle objects. The Deserialize method needs to know that it will deserialize two Rectangle objects. If you attempt to extract the information of this file into any other type of object, a runtime exception will occur.
To deserialize the contents of a file, create a formatter object as you did for the serialization process, by using one of the following statements (depending on the type of serialization):
Dim SFormatter As Soap.SoapFormatter
Dim BFormatter As BinaryFormatter
Code language: PHP (php)
Then establish a stream to the source of the serialized data, which in our case is the Shapes.bin file:
Dim Strm As New FileStream("..\Objects.Bin", FileMode.Open)
Code language: PHP (php)
Finally, deserialize the stream’s data by calling the Deserialize method. The Deserialize method accepts a single argument, which is the stream from which the data is coming, and it returns an object, which is the persisted object. We usually cast the object returned by the Deserialize method to the appropriate type:
Dim R1, R2 As Rectangle
R1 = CType(SFormatter.Deserialize(Strm), Rectangle)
R2 = CType(SFormatter.Deserialize(Strm), Rectangle)
Code language: PHP (php)
You can serialize as many objects as you like into the same stream, one after the other, and read them back in the same order. You can open the files with the serialized data and view their data. The contents of a SOAP file with two serialized Rectangle objects is shown next:
<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:clr="http://schemas.microsoft.com/soap/encoding/clr/1.0"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<a1:Rectangle id="ref-1" xmlns:a1="http://schemas.microsoft.com/clr/nsassem
/System.Drawing/System.Drawing%
2C%20Version%3D2.0.3600.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%
3Db03f5f7f11d50a3a">
<x>0</x>
<y>0</y>
<width>100</width>
<height>100</height>
</a1:Rectangle>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:clr="http://schemas.microsoft.com/soap/encoding/clr/1.0"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<a1:Rectangle id="ref-1" xmlns:a1="http://schemas.microsoft.com/clr/nsassem
/System.Drawing/System.Drawing%
2C%20Version%3D2.0.3600.0%2C%20Culture%3D
neutral%2C%20PublicKeyToken%3Db03f5f7f11d50a3a">
<x>65</x>
<y>30</y>
<width>19</width>
<height>199</height>
</a1:Rectangle>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Code language: HTML, XML (xml)
You’ll never have to create your own SOAP files, so don’t panic if they look complicated. There are, however, a few points of interest. First, you see a reference to the System.Drawing class, which indicates that the serialized data can’t be used outside the context of the Framework; this file contains serialized data describing an instance of a specific class. The section of the file with the data contains the values of the two basic properties of the Rectangle object. Second, the SOAP format uses an XML notation to delimit its fields, but it’s not an XML file. If you attempt to open the same file with Internet Explorer, you’ll see a message indicating that it’s not a valid XML document. Don’t worry if you’re not familiar with XML; I’ll discuss this format a little later in this chapter. Just keep in mind that SOAP is not the same as XML, even though they’re similar. If you remove the SOAP-related tags, you’ll be left with a valid XML file.
Serializing Collections
Serializing a collection is quite similar to serializing any single object, because collections are objects themselves. The second argument to the Serialize method is the object you want to serialize, and this object can be anything, including a collection. To demonstrate the serialization of an ArrayList, we’ll modify the previous code a little, so that instead of persisting individual items, it will persist an entire collection. Declare the two Rectangle objects as before, but append them to an ArrayList collection. Then add a few Color values to the collection, as shown in Listing 12.2, which serializes an ArrayList collection to the file C:\ShapesColors.bin.
Listing 12.2: Serializing a Collection
Private Sub Button2 Click(...) Handles Button2.Click
Dim R1 As New Rectangle()
R1.X = 1
R1.Y = 1
R1.Width = 10
R1.Height = 20
Dim R2 As New Rectangle()
R2.X = 10
R2.Y = 10
R2.Width = 100
R2.Height = 200
Dim shapes As New ArrayList()
shapes.Add(R1)
shapes.Add(R2)
shapes.Add(Color.Chartreuse)
shapes.Add(Color.DarkKhaki.GetBrightness)
shapes.Add(Color.DarkKhaki.GetHue)
shapes.Add(Color.DarkKhaki.GetSaturation)
Dim saveFile As FileStream
saveFile = File.OpenWrite("C:\ShapesColors.bin")
saveFile.Seek(0, SeekOrigin.End)
Dim formatter As BinaryFormatter = New BinaryFormatter()
formatter.Serialize(saveFile, shapes)
saveFile.Close()
MsgBox("ArrayList serialized successfully")
End Sub
Code language: PHP (php)
The last three calls to the Add method add the components of another color to the collection. Instead of adding the color as is, we’re adding three color components, from which we can reconstruct the color Color.DarkKhaki. Then we proceed to save the entire collection to a file by using the same statements as before. The difference is that we don’t call the Serialize method for each object. We call it once and pass the entire ArrayList as an argument.
Deserializing Collections
To read a file with the description of an object that has been persisted with the Serialize method, you simply call the formatter object’s Deserialize method and assign the result to an appropriately declared variable. In the preceding example, the value returned by the Deserialize method must be assigned to an ArrayList variable. The syntax of the Deserialize method is the following, where str is a Stream object pointing to the file with the data:
object = Bformatter.Deserialize(str)
Because the Deserialize method returns an Object variable, you must cast it to the ArrayList type with the CType() function. To use the Deserialize method, declare a variable that can hold the value returned by the method. If the data to be deserialized is a Rectangle, declare a Rectangle variable. If it’s a collection, declare a variable of the same collection type. Then call the Deserialize method and cast the value returned to the appropriate type. The following statements outline the process:
Dim object As <type>
{ code to set up a Stream variable (str) and BinaryFormatter}
object = CType(Bformatter.Serialize(str), <type>)
Code language: HTML, XML (xml)
Listing 12.3 is the code that retrieves the items from the ShapesColors.bin file and stores them into an ArrayList. I added a few statements to print all the items of the ArrayList.
Listing 12.3: Deserializing a Collection
Private Sub Button1 Click(...) Handles Button1.Click
Dim readFile As FileStream
readFile = File.OpenRead("C:\ShapesColors.bin")
Dim BFormatter As BinaryFormatter
BFormatter = New BinaryFormatter()
Dim Shapes As New ArrayList()
Dim R1 As Rectangle
Shapes = CType(BFormatter.Deserialize(readFile), ArrayList)
Dim i As Integer
TextBox1.AppendText("The ArrayList contains " & Shapes.Count & _
" objects " & vbCrLf & vbCrLf)
For i = 0 To Shapes.Count - 1
TextBox1.AppendText(Shapes(i).ToString & vbCrLf)
Next
End Sub
Code language: PHP (php)
You can find the code presented in this section in the SimpleSerialization sample project. The application’s main form contains buttons to serialize and deserialize both individual objects and collections in binary and SOAP formats. The SOAP-serialized data are displayed in a TextBox control on the form, as shown in Figure 12.1.
The serialization classes can substantially simplify an application’s code because they allow you to save objects, or large sets of objects, with a few statements. Moreover, you can easily deserialize the data from within any other application. A fairly common task in programming is to save large sets of data to a file and read them back in a later session. You’ve seen two such examples so far: the WordFrequencies application of Chapter, ‘‘Storing Data in Collections,” persisted a collection of words and their frequencies to a disk file, and the Globe application of section, “The TreeView and ListView Controls,” persisted the Nodes collection of a TreeView control to a file between sessions. I didn’t discuss the code in the corresponding chapters, and this is a good place to explain the code that serializes HashTables and the Nodes collection.