Serialization is a useful process when you're dealing with objects and information. .NET lets you perform this process in several different ways, two of which will be covered in this article. Keep reading to get a better handle on what serialization is and how to use it effectively.
Contributed by Ayad Boudiab Rating: / 6 February 10, 2009
Serialization is defined as the process of storing the state of an object to a storage medium. In other words, the object's bits and pieces are converted to some type of format and persisted (stored) somewhere.
We serialize an object so we can re-create it at a later stage or make it sharable between application domains. As developers, we can write our own functions that store and retrieve the fields within a class.
However, that amounts to a lot of code, and that is what the serialization classes save us from doing. Moreover, if you are not completely satisfied with the serialization functionalities, you can tap into the serialization process and provide your own additions. In .NET, there are three different ways to serialize an object:
(1) Binary serialization
(2) XML serialization
(3) SOAP serialization
In this article, we will discuss binary serialization and XML serialization. The details of the SOAP serialization are left to a future article.
With binary serialization, the public and private fields of the object, in addition to the class name and the assembly, are converted to a stream of bytes. The process of deserialization will rebuild the original object from the stream. Binary serialization is very efficient, but it is limited to the .NET framework. By that I mean I cannot use a Java application to deserialize an object serialized by a .NET-compatible language. With XML serialization, on the other hand, it is doable since the object is serialized as an XML file, which other languages (not just .NET) will be able to read.
The first step in serializing an object is to use the[Serializable]attribute. This attribute is placed above the class declaration. When designing applications, it is very important to decide which classes will be serializable as early in the development process as possible, since making the change later will be more complicated. When in doubt, always mark your class as serializable. Let's start with the[Serializable]attribute. To declare a class serializable, do the following:
[Serializable]
class Book
{
private string isbn;
public string ISBN
{
get { return isbn; }
set { isbn = value; }
}
private string title;
public string Title
{
get { return title; }
set { title = value; }
}
private string author;
public string Author
{
get { return author; }
set { author = value; }
}
public Book()
{
isbn = "";
title = "";
author = "";
}
public Book(string isbn, string title, string author)
The book class contains the usual declaration with the isbn, title, and author fields. The corresponding properties provide public access to the private fields. We added two constructors and overrode theToString()method. The only addition here is the[Serializable]attribute added to the class declaration. This attribute is signaling to the .NET Framework that objects of this class could be written to a storage medium.
Please note that the serializable attribute is not inherited. So, if class B inherits from class A, and A is [Serializable], B will NOT automatically be [Serializable]. You need to add the[Serializable]attribute to B as well.
Now that the class is serializable, let's store an instance of this class in a file. To do so, we use theBinaryFormatterclass:
IFormatter formatter = new BinaryFormatter();
Since the instance of the class is stored in a file, it is clear that we need a stream:
Stream stream = new FileStream("book.bin", FileMode.Create,
FileAccess.Write, FileShare.None);
This declaration specifies that we are creating aFileStreamfor writing, and the file name is book.bin. The last step is to call theSerialize()method of theBinaryFormatter to write the object to the file:
formatter.Serialize(stream, favoriteBook);
We can place those calls in a handy method that we can call any time we need to serialize a book object:
Note: in order to use theBinaryFormatter, make sure you add the following "using" statements:
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
Now that the content of the object is stored in the file, you can retrieve it later on in the application by deserializing the object. We can use theDesialize()method from theBinaryFormatterclass. Here is the method:
private static Book DeserializeBook()
{
IFormatter formatter = new BinaryFormatter();
Stream stream = new FileStream("book.bin", FileMode.Open,
FileAccess.Read, FileShare.Read);
Book b = (Book)formatter.Deserialize(stream);
stream.Close();
return b;
}
We create the usual objects: aBinaryFormatterto deserialize the content, and a FileStreamobject (but for reading this time). When deserializing the stream, make sure the result is cast to the appropriate object type (Bookin this case).
Finally, we can create aBookobject and callSerializeBook()andDeserializeBook()in the main method as follows:
static void Main(string[] args)
{
Book favoriteBook = new Book("0-7356-2527-1",
"Programming with ASP.NET 3.5","Dino Esposito");
Console.WriteLine("Serializing Book...");
SerializeBook(favoriteBook);
Console.WriteLine("Book serialized");
Console.WriteLine("Deserializing Book...");
Book myBook = DeserializeBook();
Console.WriteLine(myBook); //calling ToString()
Console.ReadLine();
}
After serializing theBookobject, the content of the file might look like the following:
This look like garbage data, but you can see the title and the author strings. This is about it as far as serializing and deserializing objects using theBinaryFormatter, which is very powerful but limited to .NET applications.
Some classes might contain sensitive information that you would rather not serialize. To handle this, just tag the appropriate field with the[NonSerialized]attribute, like so:
[NonSerialized] public int id;
This will inform .NET to ignore this field when serializing the object.
It is very important to note that every member in the class will be serialized, including private members. If that is an issue, then you need to look at XML serialization. Equally as important, the constructor is not called when an object is deserialized for performance reasons.
XML serialization converts the public fields and properties of an object into an XML stream that conforms to a specific XML Schema. XML serialization does not include type information, unlike binary serialization, which does. For example, if I have an employee object that belongs to a Company namespace, there is no guarantee that it is deserialized into an object of the same type.
The class that needs to be serialized using XML serialization will be tagged with the[Serializable]attribute (in the same way as with binary serialization):
[Serializable]
public class Book
{...}
In this case, however, a classmusthave a default constructor to be serialized by the XML Serializer. Here is the class declaration:
[Serializable]
public class Book
{
private string isbn;
public string ISBN
{
get { return isbn; }
set { isbn = value; }
}
private string title;
public string Title
{
get { return title; }
set { title = value; }
}
private string author;
public string Author
{
get { return author; }
set { author = value; }
}
public Book()
{
isbn = "";
title = "";
author = "";
}
public Book(string isbn, string title, string author)
To serialize the book object into an XML file, we need theXmlSerializerclass and theStreamWriterclass:
XmlSerializer serializer = new XmlSerializer(typeof(Book));
StreamWriter writer = new StreamWriter("Book.xml");
TheXmlSerializerclass expects the type of object being serialized (Bookin this case). With theStreamWriterconstructor, you specify the name of the XML file where the object will be serialized. Note in this case that we did not specify a path; the file will be created in the Debug folder within the Bin folder. Other than that, theSerializeBook()andDeserializeBook()methods are similar to those of the binary formatter:
If you look carefully at the XML file, you notice that the tags start with upper case letters, which means that they represent the properties, not the fields. This illustrates the fact that when using XML serialization, only the public elements of the class are serialized (not the private ones).
Conclusion
The.NET framework provides very powerful and flexible serialization classes. Two important categories are binary serialization and XML serialization. Use binary serialization when working within the boundaries of .NET applications. XML serialization is very handy when serialized objects are used by non-.NET applications. Another key distinction is that binary serialization serializes public and private members, while XML serialization only serializes public members.