Serialization is the process of saving the state of an object by converting it to a stream of bytes. The object can then be persisted to file, database, or even memory. The reverse process of serialization is known as deserialization (see Figure A). In this article, I discuss the uses of serialization and various techniques that can be used to perform serialization. I also take a look at how serialization works and how I can selectively prevent certain members of an object from being serialized.
Uses for serialization
Serialization is used in many scenarios, but the main purpose is to save the state of an object in order to have the ability to recreate the same object when required. It is an important to let the user save work and then be able to continue from that point at a later time. This is a common need in various tools and applications. Serialization is also used in creating a clone of an object.
Another important need for serialization arises when the object is required to travel electronically over wire. In such cases the objects are serialized and deserialized. In fact, serialization is one of the fundamental requirements for techniques such as .NET Remoting.
Even the hibernation mode in the Windows Operating system can be considered a form of serialization.
Types of serialization
The .NET Framework provides certain built-in mechanisms which can be used to serialize and deserialize objects. This functionality can be found in the System.Runtime.Serialization and the System.Xml.Serialization namespaces of the .NET Framework.
Serialization in .NET can be classified into four types as shown in Figure B:
This classification arises from the format in which the data in the object is persisted. Each of the serialization techniques mentioned have different capabilities and each excel in specific scenarios. The XML serialization technique can convert only the public properties and fields of an object into an XML format. The XML serialization is also known as shallow serialization.
This inability of the XMLSerializer to serialize the private fields of an object is overcome by the SOAP and binary serialization techniques. In the binary and SOAP serialization techniques, the state of the entire object is serialized into a stream of bytes. In cases where the object contains a reference to other objects, even those are serialized. This type of serialization is known as deep serialization.
In addition to these techniques, the .NET Framework also provides the developer control over the serialization process. This can be achieved by implementing the ISerializable interface, which will be discussed separately under custom serialization in the next part of this article.
The SOAP and binary serialization functionality is provided by means of various Formatters in the .NET Framework. Aligned with the classifications of XML serialization and binary serialization, the .NET Framework also provides the SoapFormatter and the BinaryFormatter classes. These classes implement the IRemotingFormatter and the IFormatter interfaces.
The main methods which encapsulate the functionality of serialization are the Serialize and Deserialize methods. The SoapFormatter and the BinaryFormatter are the concrete classes which enable the serialization process within the .NET Framework.
Let us now take a look at some code. The code in Listing A shows a sample class being serialized and deserialized in C#.
An instance of the SoapFormatter object is created and the Serialize method is called and a FileStream is passed to enable serialization. The technique for using a binary formatter would be the same except that instead of the SoapFormatter, an instance of the BinaryFormatter would need to be created.
Comparison: Which technique to use?
The XmlSerializer can be used when you need the data in the object to be stored in an XML Format. However, this serialize has the limitation that it can serialize only the public fields of an object.
The SoapFormatter is ideal in scenarios where you need interoperability. This is ideal in applications spanning heterogeneous environments.
The BinaryFormatter generates a very compact stream when an object is serialized as compared to the other two techniques and hence is useful when data needs to travel electronically across the wire. This is appropriate when the applications do not involve heterogeneous environments.
The developer would need to mark a class as serializable using the appropriate attribute in order for the object of that class to indeed be serializable. In fact, the serialization feature is a design time issue because an object cannot be made serializable at runtime.
The code snippet below shows the usage of SerializableAttribute:
public class MyClass
The SerializableAttribute needs to be applied even when the class implements the ISerializable interface. When an attempt is made to serialize an object which is not marked as Serializable, the CLR throws a SerializationException.
The SerializableAttribute comes in handy whenever the object needs to cross application domains or travel over the wire. The developer does not need to write any plumbing code for the serialization process to work. Once a class is marked as serializable, if the need arises for serialization, the .NET Framework will employ reflection and automatically serialize and deserialize objects which cross application domains or participate in .NET Remoting.
In certain scenarios, it may be beneficial to serialize an object in parts. Certain objects might contain information which is sensitive and for security reasons such information should not be serialized. Also, it might not make sense to serialize certain data like the reference to another object or storing a Thread ID. This data might not be valid when the object is deserialized.
For such situations, the .NET Framework provides the NonSerialized attribute. This attribute can be used to prevent particular member variables of an object from being serialized.
The sample code in Listing B demonstrates this attribute.
In the sample code listing, if the SampleObject class were to be serialized, then the data in string variable strSecret would not.
This attribute however, does not apply to the XMLSerializer. The same results could be obtained using the XMLSerializer by making use of the XmlIgnoreAttribute class.
The code sample in Listing C shows how the same results could be obtained using XMLSerializer.
In this introductory article to serialization I looked at what serialization is and where it is used. The article also dealt with selective serialization where only parts of an object are to be serialized. The final part of this article deals with more advanced topics associated with serialization such as implementing ISerializable and ICloneable.