Serialization is a process which stores an object as linear sequence of bytes. Deserialization is an opposite process which converts those bytes into the object. Those methods let us simply save object into a stream and then i.e. move it to another computer through the network.
The first way to serialize objects is using the BinaryFormatter. This formatter is the most efficient solution. Below I demonstrate how to use with
Person type.
First definition of Business object:
[Serializable]
public class Person : IDeserializationCallback
{
#region Fields
private string _name;
private string _surname;
private int _age;
[NonSerialized]
private int _totalDays;
#endregion
#region Properties
public string Name
{
get { return this._name; }
}
public string Surname
{
get { return this._surname; }
}
public int Age
{
get { return this._age; }
}
public int TotalDays
{
get { return this._totalDays; }
}
#endregion
#region Constructors
public Person(string name, string surname, int age)
{
this._name = name;
this._surname = surname;
this._age = age;
}
#endregion
#region Methods
public void UpdateTotalDays()
{
this._totalDays = this._age * 365;
}
#endregion
#region IDeserializationCallback Members
public void OnDeserialization(object sender)
{
this.UpdateTotalDays();
}
#endregion
}
As you can see this type implements IDeserializationCallback interface. This interface contains only one method
OnDeserialization, which is invoked when object is deserializing. So as a content of this method, we can put any initializing methods i.e. the Person type has a
TotalDays property but this value in not serialized. That means if we serialize object and then deserialize it we will not able to see old value of
TotalDays. Normally this property is counted by launching
UpdateTotalDays method. So by taking advantage of IDeserializationCallback we can point that method to be execute while deserializing.
Second step is a static Serializer type:
public static class Serializer
{
#region Fields
public static readonly string SerializePath = @"c:\object.data";
#endregion
#region Methods
public static void Serialize(object graph)
{
FileStream serializationStream = new FileStream(Serializer.SerializePath, FileMode.OpenOrCreate);
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(serializationStream, graph);
serializationStream.Close();
}
public static object Deserialize()
{
FileStream serializationStream = new FileStream(Serializer.SerializePath, FileMode.Open);
BinaryFormatter bf = new BinaryFormatter();
object graph = bf.Deserialize(serializationStream);
serializationStream.Close();
return graph;
}
#endregion
}
This type is responsible for saving to and loading from object.data file into the Person type. Below I pasted the NUnit test which shows how the
Serializer type works.
[Test]
public void SerializeAndDeserializeTest()
{
Person p = new Person("Jarek", "Jurczyk", 26);
p.UpdateTotalDays();
Assert.AreEqual("Jarek", p.Name);
Assert.AreEqual("Jurczyk", p.Surname);
Assert.AreEqual(26, p.Age);
Assert.AreEqual(9490, p.TotalDays);
Serializer.Serialize(p);
FileInfo fi = new FileInfo(Serializer.SerializePath);
Assert.AreEqual(true, fi.Exists);
p = null;
Assert.IsNull(p);
p = Serializer.Deserialize()as Person;
Assert.AreEqual("Jarek", p.Name);
Assert.AreEqual("Jurczyk", p.Surname);
Assert.AreEqual(26, p.Age);
Assert.AreEqual(9490, p.TotalDays);
}
More information:- If you don't want to serialize field set the attribute [NonSerialized] (you can apply on private fields)
- Never change the name of field or class if the object is already serialized
- Never remove serialized fields
- If class has already been serialized add the new field but use the [OptionalField]
- Don't apply the [NonSerialized] for fields which have been already serialized in previous version
In the next post I will describe the SoapFormatter
Labels: .NET, BinaryFormatter, Serialization