BlackWaspTM
.NET Framework
.NET 1.1+

Binary Serialization (2)

A standard problem with object-oriented languages is that of persisting object state. Binary serialization allows single objects or complex models to be converted to binary streams, which may be stored in files or transported to other systems.

Serialization Classes

The binary serialization process uses classes from the System.Runtime.Serialization and System.Runtime.Serialization.Formatters.Binary namespaces. In the sample code, we will serialize an object and store the resultant information in a file. This uses functionality from the System.IO namespace. To simplify the code for all of the classes used, add the following using directives to the code file.

using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

The first object required to perform serialization is a formatter. Formatters are responsible for converting objects to serialized information and they implement the IFormatter interface. To create a binary formatter, add the following line of code:

IFormatter formatter = new BinaryFormatter();

When the formatter is used, the information is sent to a stream. In order that you can easily view the data, we will use a FileStream and store the serialized object in a file. As FileStreams implement the IDisposable interface, we should call the Dispose method when we have finished the process. To do so automatically, we can create the stream within a using statement. The following code creates a FileStream for a file named "car.bin" in the "c:\test" folder. You may wish to change the name and location of the file.

using (FileStream stream = new FileStream(@"c:\Test\car.bin", FileMode.Create))
{
}

With the stream prepared, the Serialize method of the formatter can be executed. This method accepts two arguments. The first is the stream that the serialized information should be sent to. The second is the object to convert. Add the following code between the braces of the using statement.

formatter.Serialize(stream, car);

You can now execute the program. When it completes, the file should have been created.

Deserializing Objects

To convert serialized information back to objects, you can call the formatter's Deserialize method. This method accepts a single argument containing the stream that will provide the data. The method returns an object that can be cast to the desired type.

The following code demonstrates deserialization by opening the previously created file and reusing the same binary formatter. Note that the output contains both the public property and private field values that were serialized earlier.

Car car2;
using (FileStream stream = new FileStream(@"c:\Test\car.bin", FileMode.Open))
{
    car2 = (Car)formatter.Deserialize(stream);
}
Console.WriteLine(car2);    // Outputs "Red Coupe, 1 crash(es)."

Common Serialization Problems

There are several common problems reported when using serialization. Often, when calling the Serialize method, an exception similar to that shown below is thrown:

'Test.Car' in Assembly 'Test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'
is not marked as serializable.

This exception indicates that a [Serializable] attribute is missing. If you see the exception, check that your class has the attribute set. If it does, check that all fields and properties use types that are serializable. Finally, if you are working with classes in inheritance relationships and are serializing a base type, make sure that subclasses that may be substituted with the base class are also marked as serializable.

A second commonly experienced problem is that the constructor for an object is not executed when data is deserialized. You should ensure that code in the constructor is not essential in this scenario.

23 May 2010