Wednesday, 3 October 2012

C# Deserialization and constructor initialization

This is an example how to recreate non serialized member of the class on deserialization.

class TestSerialization
{
  [Test]
  public void Test()
  {
    var parent = new Parent(2,3);
 
    // serialize
    byte[] data = SerializationHelper.Serialize(parent);
    // deserialize
    var parentCopy = SerializationHelper.Deserialize(data) as Parent;
 
    Assert.AreEqual(2, parentCopy.Value1);
    //confirm that constructor is not called on deserialization
    Assert.AreEqual(6, parentCopy.Value2);
  }
 
  [Serializable]
  class Parent
  {
    public Parent(int value1, int value2)
    {
      _value1 = value1;
      _value2 = value2 * 2;
     //Child object is not serialized, so needs to be recreated on deserialization (see below)
      _child = new Child() { Value1 = _value1, Value2 = _value2 };
    }
 
    private int _value1;
    private int _value2;
 
    [NonSerialized]
    private Child _child;
 
    public int Value1 { get { return _child.Value1; } }
    public int Value2 { get { return _child.Value2; } }
 
    [OnDeserialized]
    private void Init(StreamingContext context)
    {
      //this is the place where we recreate child object
      _child = new Child() { Value1 = _value1, Value2 = _value2 };
    }
  }
 
  //this object is not Serializable
  class Child
  {
    public int Value1 { get; set; }
    public int Value2 { get; set; }
  }
 
  public class SerializationHelper
  {
    private static readonly BinaryFormatter Fmt = new BinaryFormatter();
 
    public static byte[] Serialize(object obj)
    {
      if (obj == null)
        throw new ArgumentNullException("obj");
      // serialize to memory
      var s = new MemoryStream();
      Fmt.Serialize(s, obj);
      s.Flush();
      return s.ToArray();
    }
 
    public static object Deserialize(byte[] data)
    {
      var os = new MemoryStream(data);
      return Fmt.Deserialize(os);
    }
  }
}