XML Serialization/Deserialization of Immutable Objects

Immutable objects are valuable in many ways.  They are the cornerstone of many functional languages and help to greatly reduce complexity.  We don't have to worry about state so references can be shared without the usual worry about nasty side effects and so we don't have to sit around looking at the code editor scratching our heads thinking: "How did the value get to be X?".  Even difficult multi-threading concurrency issues go away with immutability.  Also, we can treat immutable objects more like mathematical entities and adding operators makes the code consuming them even simpler.

The problem is when we want to pass these objects around to disconnected systems and persist them.  If the object is immutable it is not as easy to rebuild the instance because we have only 'getters' and no 'setters' so we have to approach it differently than we would with a mutable object.  The solution is using the [DataContract] and [DataMember] attributes in the correct places.

Let's say we have an immutable 'Dog' class:

public class Dog

{

    public Dog(String name)

    {

        m_Name = name;

    }

 

    private readonly String

        m_Name;

 

    public String Name { get { return m_Name; } }

}

 

If we want to serialize, the serialization engine needs access to the read only property.  We can accomplish this by adding a reference to System.Runtime.Serialization and decorating our 'Dog' class with a [DataContract] attribute and decorating our read only member variable with the [DataMember] attribute.

[DataContract]

public class Dog

{

    public Dog(String name)

    {

        m_Name = name;

    }

 

    [DataMember(Name="Name")]

    private readonly String

        m_Name;

 

    public String Name { get { return m_Name; } }

}

 

And that's pretty much it, now we can serialize and deserialize our immutable object with a DataContractSerializer.

I'll add the code for the serialization and have it live in the dog class below so you can see the implementation.  Just a side note… The serializer can live anywhere and it is not required that it be a member variable of the class being serialized as in the following code sample.

[DataContract]

public class Dog

{

    public Dog(String name)

    {

        m_Name = name;

    }

 

    private static readonly DataContractSerializer

        c_Serializer = new DataContractSerializer(typeof(Dog));

 

    [DataMember(Name="Name")]

    private readonly String

        m_Name;

 

    public String Name { get { return m_Name; } }

 

    public String ToXml()

    {

        using(MemoryStream stream = new MemoryStream())

        {

            c_Serializer.WriteObject(stream, this);

            stream.Position = 0;

 

            using (StreamReader reader = new StreamReader(stream))

            {

                return reader.ReadToEnd();

            }

 

        }

    }

 

    public static Dog FromXml(String str)

    {

     

        using(MemoryStream stream = new MemoryStream())

        using(StreamWriter writer = new StreamWriter(stream))

        {

            writer.Write(str);

            writer.Flush();

 

            stream.Position = 0;

 

            return c_Serializer.ReadObject(stream) as Dog;

 

        }

       

    }

}

 

 And now we could consume our class with the following code

Dog fido = new Dog("Fido");

 

String flattenedFido = fido.ToXml();

 

Dog reconstitutedFido = Dog.FromXml(flattenedFido);

 

String name = reconstitutedFido.Name;

 
Until next time,
Happy coding


Similar Articles