11 October 2007

1. Serialization - BinaryFormatter

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: , ,

0 Comments:

Post a Comment

<< Home