Serialization and Deserialization


Serialization is a concept that should be familiar to Java developers. It is used to create a representation of an object where the state of the object can be persisted and transported; the formatted representation of an object can be a stream of bytes, for example, or an XML document. There are many types of Stream members that we can serialize an object to, for example a FileStream or NetworkStream. Objects can be serialized and recovered later via a process called deserialization, which will use the formatted value and reconstruct it to form a .NET object. Formatters determine the rules for serialization so that we can specify what we want the serialized object to look like. In practice we will rarely need any other formatters except those that have been provided with the .NET Framework; these include a binary formatter, an XML formatter and a SOAP formatter. The binary formatter will serialize an object including all field values to a byte stream, which can be written to a file or network endpoint. The XML formatter will format the object to an XML document representation that can be written to any stream. The SOAP formatter will serialize an object to the Simple Object Access Protocol, which is an XML-based protocol (now a standard in v1.1), which is used to invoke a web service method.

Using deserialization, we can create several copies of the same object from a serialized source such as a file on disk or a network stream. Conceptually, an object is serialized to a stream to make the programming model simple and abstract, but this really excels when objects are transferred across the network. Using sockets, we can format an object using a binary formatter at the client, and recreate the same object at the server.

In this example, we'll serialize an object to a disk file and then reconstruct the object using deserialization. The following namespaces must be used to serialize objects. In order to have access to both files and streams we have to use the System.IO namespace as well. In this example we will cover the SOAP to illustrate what the output will look like when serialized but in practice we may wish to choose either one based on the circumstances. For example, the Binary Formatter will result in an object representation containing far fewer bytes, so we can use this for enhanced performance. Since the SOAP Formatted object is a standard it can be reconstructed by another programming language such as Java, which makes object serialization much more interoperable. The following was added to the copy_ctors.cs file. The new code file is called serializable_deserializable.cs:

    using System.Runtime.Serialization;    /*we won't be using the Binary Formatter but if you need to use it you    must define the following using statement*/    using System.Runtime.Serialization.Formatters.Binary;    using System.Runtime.Serialization.Formatters.Soap; 

Remember the teach reference created earlier when discussing member-wise cloning:

     Teacher teach3 = (Teacher)teach2.Clone(); 

We can revise the definition of the Teacher class by adding the Serializable attribute to it, which specifies that the class can be serialized. This is necessary because the object will be checked for this attribute when we use a formatter to serialize it, and if it is not present a SerializationException will be thrown.

     [Serializable()]     public class Teacher : ICloneable 

The code below, which is included in the Main() method, will create a file teacher.xml if it doesn't already exist and return a FileStream object that can be used to serialize the Teacher object to disk. This process will be done using SoapFormatter object. The Serialize() method of the SoapFormatter class is invoked with the FileStream and the Teacher object as parameters.

         FileStream fTeacher = File.Open("C:\\teacher.xml",                                          FileMode.OpenOrCreate,                                          FileAccess.ReadWrite);         SoapFormatter sfTeacher = new SoapFormatter();         sfTeacher.Serialize(fTeacher, teach3); 

In this example the same stream is used to serialize and deserialize the object, which means that we have to ensure that the stream pointer is reset to the beginning, or else an exception will be thrown.

         fTeacher.Position = 0; 

The Deserialize() method is used with the open FileStream and will read everything from the stream and reconstitute it as a Teacher object. We can then check that this has been done correctly by printing out its field values.

     Teacher teach4 = (Teacher)sfTeacher.Deserialize(fStream);     Console.WriteLine("Details:{0}, {1}, {2}",         teach4.Grade, teach4.Dept, teach4.Salary); 

This whole process can be used to reconstruct the Teacher object instance from the file on disk. From the code above we can see that we don't actually have to use the constructor to recreate the Teacher object; we call the Deserialize() method reading from the FileStream and then recast to a Teacher type. This technique is widely used to restore the state of an application, so that we take regular snapshots and save objects, as the idea behind the use of object databases to persist objects is gaining much ground in the development community, similar to the use of Java EJB Entity Beans, which are serializable. Using serialization is not just an alternative to cloning, it is complimentary – cloning can be used to replicate an object instance on the fly whereas serialization can be used to persist an object instance or transport it and have it reconstructed outside of the application boundaries.

We actually have just as much control over the serialization process as we have over the cloning process, and we can implement this in our serializable classes with ease. Field values can be marked as to whether they should be serialized or whether they should not be serialized. The mechanism is as simple as adding another attribute as depicted below to the fields that shouldn't be serialized.

     [NonSerialized]     private string dept = String.Empty; 

The Teacher object that has been serialized here is reproduced in serialized form. Much of the information enclosed in this is beyond the scope of the chapter and irrelevant to the understanding of serialization. It has been reproduced here to illustrate the effect of the NonSerialized attribute that was used above the dept field. We can see a tag in the SOAP XML below called a1:Teacher, and nested within this are two tags, grade and salary, which contain the values of these fields. Notice that the dept field hasn't been reproduced as it was marked NonSerialized. To generate this XML code, compile and run the serializable_deserializable.cs file, and type the following in the command prompt window:

     C:\Class Design\Ch 05> type \teacher.xml     <SOAP-ENV:Envelope        xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance        xmlns:xsd="http://www.w3.org/2001/XMLSchema"        xmlns:SOAP-ENC=http://schemas.xmlsoap.org/soap/encoding/        xmlns:SOAP-ENV=http://schemas.xmlsoap.org/soap/envelope/        xmlns:clr="http://schemas.microsoft.com/soap/encoding/clr/1.0"        SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">        <SOAP-ENV:Body>         <a1:Teacher              xmlns:a1=                      "http://schemas.microsoft.com/clr/nsassem/                      CloningAndSerialization/CloningAndSerialization                      %2C%20Version%3D1.0.1056.43019%2C%20Culture                      %3Dneutral%2C%20PublicKeyToken%3Dnull">            <grade>3</grade>            <salary>23000</salary>         </a1:Teacher>       </SOAP-ENV:Body>     </SOAP-ENV:Envelope> 

In addition to this, the .NET Framework provides a rich XML serialization model, which can be used in a manner similar to the object serialization shown here.

The following is a very simple XML document that is saved to a file called computer.xml. From this document we can infer an XML Schema, which can be thought of as a template for the XML document. By analogy, we can suggest that the XML Schema's relationship to an XML document is reminiscent of a class's relationship to an object.

     <COMPUTER>      <HARDDRIVE>MAXTOR</HARDDRIVE>      <GRAPHICSCARD>ATI</GRAPHICSCARD>      <SOUNDCARD>CREATIVE LABS</SOUNDCARD>     </COMPUTER> 

The .NET Framework provides a tool called xsd.exe that can be used to infer an XML schema, and then from that schema generate a C# class file:

     C:\Class Design\Ch 05>xsd computer.xml 

From the schema we can derive the C# class using the /c switch.

     C:\Class Design\Ch 05>xsd /c computer.xsd 

We have now created a class called COMPUTER that has been created in a file called computer.cs with the following auto-generated code. The attributes above the class declaration are synonymous with the Serializable attribute.

     using System.Xml.Serialization;     [System.Xml.Serialization.XmlTypeAttribute(      Namespace="http://tempuri.org/computer.xsd")]     [System.Xml.Serialization.XmlRootAttribute(      Namespace="http://tempuri.org/computer.xsd", IsNullable=false)]     public class COMPUTER     {       public string HARDDRIVE;       public string GRAPHICSCARD;       public string SOUNDCARD;     } 

To use the object stored in computer.xml, we can use the System.Xml.Serialization.XmlSerializer class to deserialize the contents of the file to an object of type COMPUTER. To check whether this process worked we can print out one of the field values as below.

         XmlSerializer xs = new XmlSerializer(typeof(COMPUTER));         COMPUTER cmp =             (COMPUTER)xs.Deserialize(File.Open("computer.xml",             FileMode.Open));         Console.WriteLine("Graphics card is: {0}", cmp.GRAPHICSCARD); 




C# Class Design Handbook(c) Coding Effective Classes
C# Class Design Handbook: Coding Effective Classes
ISBN: 1590592573
EAN: 2147483647
Year: N/A
Pages: 90

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net