Tuesday, May 5, 2009

Serialization in .NET - 1

Recently while returning home from work my wife (another .NET developer) was murmuring something. On further poking she said that she has been assigned a task where she has to serialize and deserialize objects and she is afraid of serialization. What? Serialization is pretty easy, I replied back. So that’ small discussion is my motivation for writing this blog on serialization. In this and subsequent blog I will show how easy serialization is and also delve into the nitty gritties of serialization.

What is serialization?

Serialization is the process of converting an object into another format whereby the state of the object can be easily saved to a file, database or memory etc and can be recreated easily. Serialization is not only for saving the object to different medium but also for transmitting the serialized objects through the network.

Different types of serialization.

The different types of serialization are

  • Binary Serialization
  • XML Serialization
  • SOAP Serialization

Binary Serialization

Binary serialization is the process where you convert your .NET objects into byte stream. In binary serialization all the public, private, even those which are read only, members are serialized and converted into bytes. So when you want a complete conversion of your objects to bytes then one can make use of binary serialization.

XML Serialization

In XML serialization only the public properties and fields of the objects are converted into XML. The private members are not taken into consideration in XML serialization.

SOAP Serialization

Similar to XML serialization. When you serialize object to SOAP format it conforms to the SOAP specification.

Lets jump into it.

Lets see each of the above serialization one by one. We will first see binary serialization then XML serialization and finally SOAP serialization.

Suppose I have a Car class (oh no! not again, the same Car class) as shown below.

namespace Cars
{
    [Serializable]
    public class Car
    {
        private string cubicCentimeter;
        public string Color
        { get; set; }
        public string Model
        { get; set; }
        public int NoOfDoors
        { get; set; }
        public int Price
        { get; set; }
    }
}

We have seen and talked about the Car class n number of times in my other blogs so I will skip and move over, it is a very simple class with a private member variable and four public properties which are making use of Automatic Properties. Please note the Serializable attribute at the top of the class. The Seializable attribute has to be applied to any type which needs to be serialized into a binary form. If the attribute is missing from the type then the compiler will throw a “System.Runtime.Serialization.SerializationException” with the following mesage.

Type 'CLASS/TYPE NAME' in Assembly 'ASSEMBLY NAME, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable

The code to serialize the Car object into a Binary stream is as shown below.

BinaryFormatter binFor = new BinaryFormatter();
using (System.IO.FileStream fs = new System.IO.FileStream("CarObject", System.IO.FileMode.Create))
{
    Cars.Car car = new Cars.Car { Model = "BMW 7 Series", Color = "Red", NoOfDoors = 4 };
    binFor.Serialize(fs, car);               
}

In the above code we are making use of the BinaryFormatter class to serialize the Car class to a Binary stream. One can see I am making use of Object Initializers to initialize the Car object. Once the car object is initialized I am calling the Serialize method of BinaryFormatter class and passing the Car object along with the FileStream object as arguments. All the members of the Car objects are serialized and dumped into the FileStream object. Even the private variable “cubicCentimeter” of the Car class is serialized to the file stream object. The byte stream generated by the BinaryFormatter class for the Car class is pasted below.

   ÿÿÿÿ          JSerializationSample, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null   Cars.Car   cubicCentimeter<Color>k__BackingField<Model>
k__BackingField<NoOfDoors>k__BackingField<Price>
k__BackingField     Red   BMW 7 Series

One can see from the above stream that all the public properties along with their values have been serialized. Even the private member variable (highlighted in Red) has been serialized.

Isn’t serialization so easy?

Now if you mark the class with the Serializable attribute all the member variables are serialized. We have seen from the above byte stream that even the private variable is serialized and that is not an expected behavior. We won’t like our private variables to be serialized, so, to do that we can use the “NonSerialized” attribute. The modified code (highlighted in red) is shown below.

namespace Cars
{
    [Serializable]
    public class Car
    {
        [NonSerialized]
        private string cubicCentimeter;
        public string Color
        { get; set; }
        public string Model
        { get; set; }
        public int NoOfDoors
        { get; set; }       
        public int Price
        { get; set; }
        public string ClassName()
        {
            return this.GetType().ToString();
        }
    }
}

The serialized content with the NonSerialized attribute applied is pasted below.

   ÿÿÿÿ          JSerializationSample, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null   Cars.Car   <Color>k__BackingField<Model>k__BackingField<NoOfDoors>
k__BackingField<Price>k__BackingField        Red  
BMW 7 Series

If you compare the above serialized content with the previous one you can find out that the content is not having the private member variable “cubicCentimeter”.

One thing to note here is that the NonSerialized attribute can only be used with fields and cannot be used with public properties. If used the following compile time error will be thrown.

“Attribute 'NonSerialized' is not valid on this declaration type. It is only valid on 'field' declarations.”

So if you want to prevent your public properties from getting binary serialized then you cannot use Automatic Properties, instead you have to go with the good old ways of declaring properties where you declare a private member variable which will hold the value of the property and then use the NonSerialized attribute on that member variable or you can write custom serialization by implementing ISerializable interface which we will see in my subsequent blog. The sample code below shows how to restrict public property from getting serialized using the NonSerialized attribute on the member variable storing the property value.

namespace Cars
{
    [Serializable]
    public class Car
    {
        [NonSerialized]
        private string cubicCentimeter;
        public string Color
        { get; set; }
        public string Model
        { get; set; }
        public int NoOfDoors
        { get; set; }       
        [NonSerialized]
        private int price;
        public int Price
        {
            get
            {
                return price;
            }
            set
            {
                price = value;
            }
        }
        public string ClassName()
        {
            return this.GetType().ToString();
        }
    }
}

Now when the above class is serialized it will be devoid of the public property Price. The byte stream is pasted below

   ÿÿÿÿ          JSerializationSample, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null   Cars.Car   <Color>k__BackingField<Model>k__BackingField<NoOfDoors>
k__BackingField       Red   BMW 7 Series  

So using the NoSerilaized attribute we can control a particular member of a class from getting serialized.

Deserializing the object

Deserializing the object and restoring it to its previous state is also pretty easy. The below code shows how to deserialize the Car object from the binary file created from the above serialization code.

using (System.IO.FileStream fs = new System.IO.FileStream("CarObject", System.IO.FileMode.Open, System.IO.FileAccess.Read))
{
    BinaryFormatter deSerialize = new BinaryFormatter();
        Cars.Car car = (Cars.Car)deSerialize.Deserialize(fs);
}

In the above code FileStream object is used to read the binary content from a file and then the DeSerialize method of BinaryFormatter is used to deserialize the object to its state before serialization. The below screenshot shows all the properties of the Car class being read from the binary file and assigned.

image

In the next blog we will see xml serialization and related stuffs. Till then try to know more.

Sandeep

3 comments:

  1. it's the first wonderful article explaining the difference between Serialized and NonSerialized very clear during 1 hour google search. Congrats.

    ReplyDelete
  2. Thanks for the compliments. You were able to understand the difference and this article was useful to you, thats served its purpose.

    ReplyDelete
  3. Serialization Means procedure of transforming an item into another structure whereby the state of the item can be quickly stored to a computer file, data source or storage etc and can be regenerated quickly.

    ReplyDelete

Please provide your valuable comments.