Code Listings
Chapter 15: Serialization
Basic use of DataContractSerializer:
namespace SerialTest { [DataContract] public class Person { [DataMember] public string Name; [DataMember] public int Age; } }
Person p = new Person { Name = "Stacey", Age = 30 }; DataContractSerializer ds = new DataContractSerializer (typeof (Person)); using (Stream s = File.Create ("person.xml")) ds.WriteObject (s, p); // Serialize Person p2; using (Stream s = File.OpenRead ("person.xml")) p2 = (Person) ds.ReadObject (s); // Deserialize Console.WriteLine (p2.Name + " " + p2.Age); // Stacey 30
Formatting the output:
Person p = new Person { Name = "Stacey", Age = 30 }; DataContractSerializer ds = new DataContractSerializer (typeof (Person)); XmlWriterSettings settings = new XmlWriterSettings() { Indent = true }; using (XmlWriter w = XmlWriter.Create ("person.xml", settings)) ds.WriteObject (w, p); System.Diagnostics.Process.Start ("person.xml");
Overriding data member names:
[DataContract (Name="Candidate", Namespace="http://oreilly.com/nutshell")] public class Person { [DataMember (Name="FirstName")] public string Name; [DataMember (Name="ClaimedAge")] public int Age; }
Specifying a binary formatter with the data contract serializer:
Person p = new Person { Name = "Stacey", Age = 30 }; DataContractSerializer ds = new DataContractSerializer (typeof (Person)); MemoryStream s = new MemoryStream(); using (XmlDictionaryWriter w = XmlDictionaryWriter.CreateBinaryWriter (s)) ds.WriteObject (w, p); MemoryStream s2 = new MemoryStream (s.ToArray()); Person p2; using (XmlDictionaryReader r = XmlDictionaryReader.CreateBinaryReader (s2, XmlDictionaryReaderQuotas.Max)) p2 = (Person) ds.ReadObject (r);
Serializing subclasses:
[DataContract, KnownType (typeof (Student)), KnownType (typeof (Teacher))] public class Person { [DataMember] public string Name; [DataMember] public int Age; } [DataContract] public class Student : Person { } [DataContract] public class Teacher : Person { }
static Person DeepClone (Person p) { DataContractSerializer ds = new DataContractSerializer (typeof (Person)); MemoryStream stream = new MemoryStream(); ds.WriteObject (stream, p); stream.Position = 0; return (Person) ds.ReadObject (stream); }
Person person = new Person { Name = "Stacey", Age = 30 }; Student student = new Student { Name = "Stacey", Age = 30 }; Teacher teacher = new Teacher { Name = "Stacey", Age = 30 }; Person p2 = DeepClone (person); Student s2 = (Student) DeepClone (student); Teacher t2 = (Teacher) DeepClone (teacher);
Alternative to KnownType on [DataContract]:
DataContractSerializer ds = new DataContractSerializer (typeof (Person), new Type[] { typeof (Student), typeof (Teacher) } );
Object references:
[DataContract] public class Person { [DataMember] public string Name; [DataMember] public int Age; [DataMember] public Address HomeAddress; } [DataContract, KnownType (typeof (USAddress))] public class Address { [DataMember] public string Street, Postcode; }
Version tolerance:
[DataContract] public class Person : IExtensibleDataObject { [DataMember] public string Name; [DataMember] public int Age; ExtensionDataObject IExtensibleDataObject.ExtensionData { get; set; } }
Member ordering:
[DataContract] public class Person { [DataMember (Order=0)] public string Name; [DataMember (Order=1)] public int Age; }
Null and empty values:
[DataContract] public class Person { [DataMember (EmitDefaultValue=false)] public string Name; [DataMember (EmitDefaultValue=false)] public int Age; }
Data contracts and collections:
[DataContract] public class Person { [DataMember (Name="Addresses")] List<Address> _addresses; public IList<Address> Addresses { get { return _addresses; } } } [DataContract] public class Address { [DataMember] public string Street, Postcode; }
Subclassing collection elements:
[DataContract, KnownType (typeof (USAddress))] public class Address { [DataMember] public string Street, Postcode; } public class USAddress : Address { }
Customizing collection and element names:
[CollectionDataContract (ItemName="Residence")] public class AddressList : Collection<Address> { } [DataContract] public class Person { ... [DataMember] public AddressList Addresses; }
[CollectionDataContract (ItemName="Entry", KeyName="Kind", ValueName="Number")] public class PhoneNumberList : Dictionary <string, string> { } [DataContract] public class Person { ... [DataMember] public PhoneNumberList PhoneNumbers; }
Serialization and deserialization hooks:
public DateTime DateOfBirth; [DataMember] public bool Confidential; [DataMember (Name="DateOfBirth", EmitDefaultValue=false)] DateTime? _tempDateOfBirth; [OnSerializing] void PrepareForSerialization (StreamingContext sc) { if (Confidential) _tempDateOfBirth = DateOfBirth; else _tempDateOfBirth = null; }
Getting started with the binary engine:
[Serializable] public sealed class Person { public string Name; public int Age; }
Person p = new Person() { Name = "George", Age = 25 }; IFormatter formatter = new BinaryFormatter(); using (FileStream s = File.Create ("serialized.bin")) formatter.Serialize (s, p); using (FileStream s = File.OpenRead ("serialized.bin")) { Person p2 = (Person) formatter.Deserialize (s); Console.WriteLine (p2.Name + " " + p.Age); // George 25 }
[NonSerialized]:
[Serializable] public sealed class Person { public string Name; public DateTime DateOfBirth; // Age can be calculated, so there's no need to serialize it. [NonSerialized] public int Age; }
[OnDeserializing] and [OnDeserialized]
public sealed class Person { public string Name; public DateTime DateOfBirth; [NonSerialized] public int Age; [NonSerialized] public bool Valid = true; public Person() { Valid = true; } }
[OnSerializing] and [OnSerialized]
[Serializable] public sealed class Team { public string Name; Person[] _playersToSerialize; [NonSerialized] public List<Person> Players = new List<Person>(); [OnSerializing] void OnSerializing (StreamingContext context) { _playersToSerialize = Players.ToArray(); } [OnSerialized] void OnSerialized (StreamingContext context) { _playersToSerialize = null; // Allow it to be freed from memory } [OnDeserialized] void OnDeserialized (StreamingContext context) { Players = new List<Person> (_playersToSerialize); } }
[OptionalField] and versioning:
[Serializable] public sealed class Person // Version 2 Robust { public string Name; [OptionalField (VersionAdded = 2)] public DateTime DateOfBirth; }
ISerializable:
[Serializable] public class Team : ISerializable { public string Name; public List<Person> Players; public virtual void GetObjectData (SerializationInfo si, StreamingContext sc) { si.AddValue ("Name", Name); si.AddValue ("PlayerData", Players.ToArray()); } public Team() {} protected Team (SerializationInfo si, StreamingContext sc) { Name = si.GetString ("Name"); // Deserialize Players to an array to match our serialization: Person[] a = (Person[]) si.GetValue ("PlayerData", typeof (Person[])); // Construct a new List using this array: Players = new List<Person> (a); } }
Getting started with XmlSerializer:
public class Person { public string Name; public int Age; }
p.Name = "Stacey"; p.Age = 30; XmlSerializer xs = new XmlSerializer (typeof (Person)); using (Stream s = File.Create ("person.xml")) xs.Serialize (s, p); Person p2; using (Stream s = File.OpenRead ("person.xml")) p2 = (Person) xs.Deserialize (s); Console.WriteLine (p2.Name + " " + p2.Age); // Stacey 30
Attributes, names and namespaces:
public class Person { [XmlElement ("FirstName")] public string Name; [XmlAttribute ("RoughAge")] public int Age; }
XML element order:
public class Person { [XmlElement (Order = 2)] public string Name; [XmlElement (Order = 1)] public int Age; }
XmlSerializer and subclassing:
[XmlInclude (typeof (Student))] [XmlInclude (typeof (Teacher))] public class Person { public string Name; } public class Student : Person { } public class Teacher : Person { }
public void SerializePerson (Person p, string path) { XmlSerializer xs = new XmlSerializer (typeof (Person)); using (Stream s = File.Create (path)) xs.Serialize (s, p); }
Alternative:
XmlSerializer xs = new XmlSerializer (typeof (Person), new Type[] { typeof (Student), typeof (Teacher) } );
Serializing child objects:
public class Person { public string Name; public Address HomeAddress = new Address(); } public class Address { public string Street, PostCode; }
Person p = new Person(); p.Name = "Stacey"; p.HomeAddress.Street = "Odo St"; p.HomeAddress.PostCode = "6020";
Subclassed child objects, solution 1:
[XmlInclude (typeof (AUAddress))] [XmlInclude (typeof (USAddress))] public class Address { public string Street, PostCode; } public class USAddress : Address { } public class AUAddress : Address { } public class Person { public string Name; public Address HomeAddress = new USAddress(); }
Subclassed child objects, solution 2:
public class Address { public string Street, PostCode; } public class USAddress : Address { } public class AUAddress : Address { } public class Person { public string Name; [XmlElement ("Address", typeof (Address))] [XmlElement ("AUAddress", typeof (AUAddress))] [XmlElement ("USAddress", typeof (USAddress))] public Address HomeAddress = new USAddress(); }
Serializing collections with the outer element:
public class Person { public string Name; [XmlArray ("PreviousAddresses")] [XmlArrayItem ("Location")] public List<Address> Addresses = new List<Address>(); }
Serializing collections without the outer element:
public class Person { public string Name; [XmlElement ("Address")] public List<Address> Addresses = new List<Address>(); }
Subclassing collection elements with the outer element:
[XmlArrayItem ("Address", typeof (Address))] [XmlArrayItem ("AUAddress", typeof (AUAddress))] [XmlArrayItem ("USAddress", typeof (USAddress))] public List<Address> Addresses = new List<Address>();
Subclassing collection elements without the outer element:
[XmlElement ("Address", typeof (Address))] [XmlElement ("AUAddress", typeof (AUAddress))] [XmlElement ("USAddress", typeof (USAddress))] public List<Address> Addresses = new List<Address>();
IXmlSerializable:
using System; using System.Xml; using System.Xml.Schema; using System.Xml.Serialization; public class Address : IXmlSerializable { public string Street, PostCode; public XmlSchema GetSchema() { return null; } public void ReadXml(XmlReader reader) { reader.ReadStartElement(); Street = reader.ReadElementContentAsString ("Street", ""); PostCode = reader.ReadElementContentAsString ("PostCode", ""); reader.ReadEndElement(); } public void WriteXml (XmlWriter writer) { writer.WriteElementString ("Street", Street); writer.WriteElementString ("PostCode", PostCode); } }
© 2007, O'Reilly Media, Inc. All rights reserved