본문 바로가기

Software/C#.Net

Serialization

Object Graphs
The Role of Object Graphs 
The set of object to serialize is referred to as an OBJECT GRAPH by CLR.
  • Object graphs provide a simple way to document how a set of objects refer to each other and do not necessarily map to classic OO relationships (such as the “is-a” or “has-a” relationship), although they do model this paradigm quite well.(Apress Pro C# 2008-P742)
  • A group of objects to serialize are called Object Graphy(Charom)
  • Each object in an object graph is assigned a unique numerical value 
  • After assigned the value, the object graph can record each object’s set of dependencies.
  • Example of class to Graph
 Real Programming CLR creates a Object Grap rule  in Humen mind 
[Serializable]
public class Radio{...} [Serializable]
class Car{public Radio..}
[Serializable] public class JamesBondCar:Car{...}
[Car 3, ref 2],
[Radio 2],
[JamesBondCar 1, ref 3, ref 2] 

 
 Configuring Objects for Serialization
[Serializable] - To make an object available to .NET serialization services
[NonSerialized] -  If you determine that a given type has some member data that should not (or perhaps cannot) participate in the serialization scheme
 
if you derive a class from a type marked [Serializable], the child class must be marked [Serializable] as well
In fact, all objects in an object graph must be marked with the [Serializable] attribute. If you attempt to serialize a nonserializable object using the BinaryFormatter or SoapFormatter, you will receive a SerializationException at runtime.
 
Defining Serializable Types
[Serializable]
public class Radio
{
   public bool hasTweeters;
   public bool hasSubWoofers;
   public double[] stationPresets;
   [NonSerialized]
   public string radioID = "XF-552RR6";   //<<--non serialized
   [Serializable]
   public class Car
   {
      public Radio theRadio = new Radio();
      public bool isHatchBack;
   }
   [Serializable]
   public class JamesBondCar : Car
   {
// A public field.
public bool canDrive; // A private field. private int carAge = 1; // Public property/private data. private string CarName = string.Empty; public string car_name { get { return CarName; } set { CarName = value; } } } }
  Public,Private
   canDrive  carAge  CarName
 BinaryFormatter O O
 SoapFormatter
 XmlSerializer
*carAge and CarName are private, but only CarName revealed by public property(car_name)

Choosing a Serialization Formatter
Formatter classes
• BinaryFormatter
    +object’s state to a stream using a compact binary format
using System.Runtime.Serialization.Formatters.Binary; //namespace 
• SoapFormatter
   + an object’s state as a SOAP message
   + System.Runtime.Serialization.Formatters.Soap namespace that is defined within a separate assembly 
   + Before using, needs reference by adding dll( System.Runtime.Serialization.Formatters.Soap.dll)
// Must reference System.Runtime.Serialization.Formatters.Soap.dll.
     using System.Runtime.Serialization.Formatters.Soap; 
• XmlSerializer
   + VS2008 or later version automatically included this dll
// Defined within System.Xml.dll.
     using System.Xml.Serialization;
 
Basic Intefaces (IFormatter & IRemotingFormatter)
public interface IFormatter
{
   SerializationBinder Binder { get; set; }
   StreamingContext Context { get; set; }
   ISurrogateSelector SurrogateSelector { get; set; }
   object Deserialize(System.IO.Stream serializationStream);
   void Serialize(System.IO.Stream serializationStream, object graph);
}
public interface IRemotingFormatter  : IFormatter
{
    object Deserialize(Stream serializationStream, HeaderHandler handler); //--Overload method--
    void Serialize(Stream serializationStream, object graph,  //--Overload method--
    Header[] headers);
}

////Using the interfaces ////
static void SerializeObjectGraph(IFormatter itfFormat, Stream destStream, object graph)
{
   itfFormat.Serialize(destStream, graph);
}

Type Fidelity Among the Formatters : choosing a formatter properly
BinarryFormatter
• The fully qualified name of the objects in the graph (e.g., MyApp.JamesBondCar)
• The name of the assembly defining the object graph (e.g., MyApp.exe)
• An instance of the SerializationInfo class that contains all stateful data maintained by the members in the object graph
SoapFormatter
  • A solid choice, when you wish to distribute objects remotely across diverse environments
  • SOAP(Simple Object Access Protocol
XmlFormatter
  • persist the public state of a given object as pure XML, as opposed to XML data wrapped within a SOAP message
  • The XmlSerializer demands that all serialized types in the object graph support a default constructor
Serializing Objects Using the BinaryFormatter
// Be sure to import the System.Runtime.Serialization.Formatters.Binary 
// and System.IO namespaces. 
static void Main(string[] args)
{
   Console.WriteLine("***** Fun with Object Serialization *****\n");
   // Make a JamesBondCar and set state.
   JamesBondCar jbc = new JamesBondCar();
   jbc.canFly = true;
   jbc.canSubmerge = false;
   jbc.theRadio.stationPresets = new double[]{89.3, 105.1, 97.1};
   jbc.theRadio.hasTweeters = true;
   // Now save the car to a specific file in a binary format.
   SaveAsBinaryFormat(jbc, "CarData.dat"); 
   Console.ReadLine();
}
static void SaveAsBinaryFormat(object objGraph, string fileName)
{
   // Save object to a file named CarData.dat in binary.
   BinaryFormatter binFormat = new BinaryFormatter();
   using(Stream fStream = new FileStream(fileName,
   FileMode.Create, FileAccess.Write, FileShare.None))
   {
      binFormat.Serialize(fStream, objGraph);
   }
   Console.WriteLine("=> Saved car in binary format!");
}
//Read from CarData.dat file
static void LoadFromBinaryFile(string fileName)
{
   BinaryFormatter binFormat = new BinaryFormatter();
   // Read the JamesBondCar from the binary file.
   using(Stream fStream = File.OpenRead(fileName))
   {
      JamesBondCar carFromDisk =
      (JamesBondCar)binFormat.Deserialize(fStream);
      Console.WriteLine("Can this car fly? : {0}", carFromDisk.canFly);
   }
}

Serializing Objects Using the SoapFormatter
// Be sure to import System.Runtime.Serialization.Formatters.Soap 
// and reference System.Runtime.Serialization.Formatters.Soap.dll.
static void SaveAsSoapFormat (object objGraph, string fileName) /*Passing objGraph*/
{
   // Save object to a file named CarData.soap in SOAP format.
   SoapFormatter soapFormat = new SoapFormatter(); /*checkpoint*/
   using(Stream fStream = new FileStream(fileName,
   FileMode.Create, FileAccess.Write, FileShare.None))
   {
      soapFormat.Serialize(fStream, objGraph); /*check point*/
   }
   Console.WriteLine("=> Saved car in SOAP format!"); 
}

Serializing Objects Using the XmlSerializer Working with this type is a bit different from working with the SoapFormatter or BinaryFormatter type
static void SaveAsXmlFormat(object objGraph, string fileName)
{
   // Save object to a file named CarData.xml in XML format.
   XmlSerializer xmlFormat = new XmlSerializer(typeof(JamesBondCar),new Type[] { typeof(Radio), typeof(Car) }); /*every time ask type*/
   using(Stream fStream = new FileStream(fileName,FileMode.Create, FileAccess.Write, FileShare.None))
   {
      xmlFormat.Serialize(fStream, objGraph);
   }
   Console.WriteLine("=> Saved car in XML format!"); 
}

Select Attributes of the System.Xml.Serialization Namespace
 XmlAttributeAttribute  The member will be serialized as an XML attribute.
 XmlElementAttribute  The field or property will be serialized as an XML element.
 XmlEnumAttribute  The element name of an enumeration member.
 XmlRootAttribute  This attribute controls how the root element will be constructed (namespace and element name).
 XmlTextAttribute  The property or field should be serialized as XML text.
 XmlTypeAttribute  The name and namespace of the XML type.

Example of JamesBondCar
1.Using Previous declared class
   
   
      ...
      true
      false
   

2.Other way
[Serializable, XmlRoot(Namespace = "http://www.intertech.com")]
public class JamesBondCar : Car
{
   [XmlAttribute]
   public bool canFly;
   [XmlAttribute]
   public bool canSubmerge;
}
XML File
//XML File


...


Serializing Collections of Objects declare the class
[Serializable,
XmlRoot(Namespace = "http://www.intertech.com")]
public class JamesBondCar : Car
{
   public JamesBondCar(bool skyWorthy, bool seaWorthy)
   {
      canFly = skyWorthy;
      canSubmerge = seaWorthy;
   }
   // The XmlSerializer demands a default constructor!
   public JamesBondCar(){}
   ...
}
/////////////////////////////////
//serialize  the collection  //
///////////////////////////////
static void SaveListOfCars()
{
   // Now persist a List<t> of JamesBondCars.
   List<jamesbondcar> myCars = new List<jamesbondcar>();
   myCars.Add(new JamesBondCar(true, true));
   myCars.Add(new JamesBondCar(true, false));
   myCars.Add(new JamesBondCar(false, true));
   myCars.Add(new JamesBondCar(false, false));
   using(Stream fStream = new FileStream("CarCollection.xml",
   FileMode.Create, FileAccess.Write, FileShare.None))
   {
      XmlSerializer xmlFormat = new XmlSerializer(typeof(List<jamesbondcar>),
      new Type[] { typeof(JamesBondCar), typeof(Car), typeof(Radio) });
      xmlFormat.Serialize(fStream, myCars);
   }
   Console.WriteLine("=> Saved list of cars!");
}
Customizing the Serialization Process System.Runtime.Serialization Namespace Core Types
 ISerializable  This interface can be implemented on a [Serializable] type to control its serialization and deserialization.
 ObjectIDGenerator  This type generates IDs for members in an object graph.
 [OnDeserialized]  This attribute allows you to specify a method that will be called immediately after the object has been deserialized.
 [OnDeserializing]  This attribute allows you to specify a method that will be called before the deserialization process.
 [OnSerialized]  This attribute allows you to specify a method that will be called immediately after the object has been serialized.
 [OnSerializing]  This attribute allows you to specify a method that will be called before the serialization process.
 [OptionalField]  This attribute allows you to define a field on a type that can be missing from the specified stream.
 SerializationInfo  In essence, this class is a “property bag” that maintains name/value pairs representing the state of an object during the serialization process.

Customizing Serialization Using ISerializable
//////////////Serializable/////////////
// When you wish to tweak the serialization process,
// implement ISerializable.
public interface ISerializable
{
   void GetObjectData(SerializationInfo info,
   StreamingContext context);
}
//////////SerializationInfo//////////////
public sealed class SerializationInfo : object
{
   public SerializationInfo(Type type, IFormatterConverter converter);
   public string AssemblyName { get; set; }
   public string FullTypeName { get; set; }
   public int MemberCount { get; }
   public void AddValue(string name, short value);
   public void AddValue(string name, UInt16 value);
   public void AddValue(string name, int value);
   ...
}
//////////Extension of Interfaces/////////////
// You must supply a custom constructor with this signature
// to allow the runtime engine to set the state of your object.
[Serializable]
class SomeClass : ISerializable
{
   protected SomeClass (SerializationInfo si, StreamingContext ctx) {...}
   ...
}