Again about differences about Binary versus Xml Serialization

In previous post I deal with the size of binary serialization vs Xml Serialization, but as my friend Marco commented, those two techniques are really different and should not be compared directly.

Binary serialization is a technique used to obtain a binary representation of an object, and then rebuild that object from it back to a real instance in memory.

Serialization is a process that permits to convert the state of an object into a form that can be stored into some durable medium (file, DB) to rebuild original object in the future or to send the object to another process or computer through network channels.

Xml Serialization in.net, has probably a wrong name, because it does not really serialize an object, it only create an XML stream with the content of all the public properties,it does not store private fields, and it is not meant to create a stream to save object state into some durable medium. Xml Serialization is meant as a technique to read and write XML stream to and from an object model. If you have a schema file, you can use xsd.exe tool to generate a set of classes that can be used to create in memory an object representation of a xml file that satisfies that schema.

A great hint that Xml serialization has little to share with binary serialization is that XmlSerializer can serialize a class that is not marked as serializable. This is possible because XmlSerializer does not really serialize the object it simply create a xml stream. If you have a class that simply dumps whenever the default constructor is called

1
2
3
4
5
6
7
8
public class Test3 
    {
        public Test3()
        {
            Console.WriteLine("Test3Constructor Call");
        }

        public String Property { get; set; }

when you deserialize an object with XmlSerializer you can see that this constructor gets called. If you deserialize an object with a BinaryFormatter the constructor is not called. This is perfectly reasonable, since serialization is meant to convert an object to a binary stream and back, so you cannot call the default constructor during deserialization because you can end in having a different object from the original one. Try this object

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
public class Test4
{
    public Test4()
    {
    }

    public Test4(String privateString)
    {
        this.privateString = privateString;
    }

    public String Property { get; set; }

    public String GetPrivateString()
    {
        return privateString;
    }

    private String privateString;
}

It has no business meaning, but if you run this code

1
2
3
4
5
6
7
8
9
Test4 t = new Test4("privatevalue");
Console.WriteLine("GetPrivateString = " + t.GetPrivateString());
MemoryStream xms = new MemoryStream();
XmlSerializer xs = new XmlSerializer(typeof(Test4));
xs.Serialize(xms, t);

xms.Position = 0;
Test4 des = (Test4)xs.Deserialize(xms);
Console.WriteLine("GetPrivateString = " + des.GetPrivateString());

You will find that the output is

1
2
GetPrivateString = privatevalue
GetPrivateString =

Thus the deserialized object is not the same of the serialized one, thus XML serialization does not guarantees that an entity would be the same after deserialization as Marco commented in the previous post. A very different situation happens if you use binary serialization.

1
2
3
4
5
6
7
8
Test4 t = new Test4("privatevalue");
Console.WriteLine("GetPrivateString = " + t.GetPrivateString());
MemoryStream bms = new MemoryStream();
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(bms, t);
bms.Position = 0;
Test4 des = (Test4) bf.Deserialize(bms);
Console.WriteLine("GetPrivateString = " + t.GetPrivateString());

The output is

1
2
GetPrivateString = privatevalue
GetPrivateString = privatevalue

Thus showing that the deserialized object has the same state. But XmlSerialization have other problems, let’s serialize and deserialize this class

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
[Serializable]
public class Testcontainer
{
    public Test test1 { get; set; }
    public Test test2 { get; set; }    
}

...

Testcontainer t = new Testcontainer();
t.test1 = t.test2 = new Test() { Property = "Test"};
MemoryStream xms = new MemoryStream();
XmlSerializer xs = new XmlSerializer(typeof(Testcontainer));
xs.Serialize(xms, t);

xms.Position = 0;
Testcontainer des = (Testcontainer)xs.Deserialize(xms);
Console.WriteLine("t.test1 == t.test2 is {0}", des.test1 == des.test2);

MemoryStream bms = new MemoryStream();
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(bms, t);
bms.Position = 0;
 des = (Testcontainer)bf.Deserialize(bms);
 Console.WriteLine("t.test1 == t.test2 is {0}", des.test1 == des.test2);

The output shows you that with XML Serialization the condition des.test1 == des.test2 is false, because Xml Serialization does not check for object identity , thus it throws exception if the object graph has a circular references.

Never use XmlSerialization to store an object into durable medium unless you are perfectly aware of what you are doing.

alk.

Tags: Serialization .Net Framework

DotNetKicks Image