1

Serialize/Deserialize objects in .Net – don’t forget to initialize

Recently in our project I had a weird exception popping up in C#. We found the problem and fixed it… but the problem was something we didn’t expect ! So I’ll post my findings here so other people can benefit from it.
I must say, I don’t know if this behaviour is anywhere described in MSDN, so could be I missed the information.

Consider this class Foo with only 1 member O1 that is Serializable.

[Serializable]
public class Foo
{
private object _O1;

public object O1
{
get { return _O1; }
set { _O1 = value; }
}

public Foo()
{
O1 = new object();
}
}

Now we are going to save an instance of this Foo class to file through Serialization ! ( here done through unittesting with NUnit )

[Test]
public void SerializeTest()
{
Foo foo = new Foo();
Assert.IsNotNull(foo.O1);

BinaryFormatter formatter = new BinaryFormatter();
formatter.AssemblyFormat = FormatterAssemblyStyle.Simple;
FileStream stream = new FileStream(@"c:\temp\foo.dat", FileMode.Create, FileAccess.Write, FileShare.None);
formatter.Serialize(stream, foo);
}

Now we have a binary representation of Foo on file, called foo.dat !
After this, we change the Foo class and add a second member called O2.

[Serializable]
public class Foo
{
private object _O2;

public object O2
{
get { return _O2; }
set { _O2 = value; }
}

private object _O1;

public object O1
{
get { return _O1; }
set { _O1 = value; }
}

public Foo()
{
O1 = new object();
O2 = new object();
}
}

And now for the big problem… we Deserialize the foo.dat file with this new Foo class code.

[Test]
public void DeserializeTest()
{
BinaryFormatter formatter = new BinaryFormatter();
FileStream stream = new FileStream(@"c:\temp\foo.dat", FileMode.Open, FileAccess.Read, FileShare.Read);
Foo foo = (Foo)formatter.Deserialize(stream);
Assert.IsNotNull(foo.O2);
}

And what do you notice ? The test wil FAIL !! Yes… what we didn’t expect was the fact that .Net somehow can initialize the Foo object without going through it’s default constructor !!
Resulting in a Foo object with a O2 member that equals NULL instead of new Object() !

This would mean that if you need to deserialize newer class versions of existing binary objects, you should use the interface ISerializable and use protected Foo(SerializationInfo info, StreamingContext context) to be sure all members ( and new members ) are serialized and initiated ?

Can anyone shed some light on this ?

[Update] Jelle has given me the correct link to the MSDN documentation that gives the answer to this phenomenon !! Thanks Jelle ! http://msdn2.microsoft.com/en-us/library/4abbf6k0(VS.71).aspx

Technorati Tags: , ,

Depechie

One Comment

  1. Hi Glenn,

    You didn’t hit a bug or anything, it’s indeed true that the BinaryFormatter instantiates objects without running their constructor.

    This is even documented on MSDN, e.g. on http://msdn2.microsoft.com/en-us/library/4abbf6k0(VS.71).aspx:

    “It is important to note that constructors are not called when an object is deserialized. This constraint is placed on deserialization for performance reasons.”

    Cheers,

    Jelle

Leave a Reply

Your email address will not be published. Required fields are marked *