using System.Collections.Generic;
using System.Xml.Serialization;
public class EmployeesListSurrogate
public List<Person> EmployeeList { get; set; }
public static implicit operator List<Person>(EmployeesListSurrogate surrogate)
return surrogate == null ? null : surrogate.EmployeeList;
public static implicit operator EmployeesListSurrogate(List<Person> employees)
return new EmployeesListSurrogate { EmployeeList = employees };
[XmlSchemaProvider("GetSchemaMethod")]
public class Person : IXmlSerializable
private string personName;
public Person(string name)
static string personXmlTypeName;
const string defaultXmlTypeName = "Person";
static string PersonXmlTypeName
if (personXmlTypeName == null)
personXmlTypeName = defaultXmlTypeName;
return personXmlTypeName;
personXmlTypeName = value;
public static IDisposable PushXmlTypeName(string xmlTypeName)
return new PushValue<string>(xmlTypeName, () => PersonXmlTypeName, val => PersonXmlTypeName = val);
public static XmlQualifiedName GetSchemaMethod(XmlSchemaSet xs)
string EmployeeSchemaFormat = @"<?xml version=""1.0"" encoding=""utf-16""?>
<xs:schema elementFormDefault=""qualified"" xmlns:xs=""http://www.w3.org/2001/XMLSchema"">
<xs:import namespace=""http://www.w3.org/2001/XMLSchema"" />
<xs:element name=""{0}"" nillable=""true"" type=""{0}"" />
<xs:complexType name=""{0}"" mixed=""true"">
var EmployeeSchema = string.Format(EmployeeSchemaFormat, PersonXmlTypeName);
using (var textReader = new StringReader(EmployeeSchema))
using (var schemaSetReader = System.Xml.XmlReader.Create(textReader))
xs.Add("", schemaSetReader);
return new XmlQualifiedName(PersonXmlTypeName);
public void WriteXml(XmlWriter writer)
writer.WriteString(personName);
public void ReadXml(XmlReader reader)
var isEmpty = reader.IsEmptyElement;
reader.ReadStartElement();
personName = reader.ReadContentAsString();
public XmlSchema GetSchema()
public override string ToString()
public struct PushValue<T> : IDisposable
public PushValue(T value, Func<T> getValue, Action<T> setValue)
if (getValue == null || setValue == null)
throw new ArgumentNullException();
this.setValue = setValue;
this.oldValue = getValue();
#region IDisposable Members
public static class PersonEmployeeListSerializerFactory
static Dictionary<Tuple<string, string>, XmlSerializer> serializers;
static object padlock = new object();
static PersonEmployeeListSerializerFactory()
serializers = new Dictionary<Tuple<string, string>, XmlSerializer>();
public static XmlSerializer GetSerializer(string rootName, string personName)
XmlSerializer serializer;
var key = Tuple.Create(rootName, personName);
if (!serializers.TryGetValue(key, out serializer))
using (Person.PushXmlTypeName(personName))
var lOverrides = new XmlAttributeOverrides();
serializers[key] = serializer = new XmlSerializer(typeof(List<Person>), lOverrides, new Type[0], new XmlRootAttribute(rootName), null);
public static void Test()
List<Person> lPersonList = new List<Person>
TestDefault(lPersonList);
var xmlOverride = TestOverride(lPersonList);
var xmlSurrogate = TestSurrogate(lPersonList);
if (!XNode.DeepEquals(XElement.Parse(xmlOverride), XElement.Parse(xmlSurrogate)))
throw new InvalidOperationException("!XNode.DeepEquals(XElement.Parse(xmlOverride), XElement.Parse(xmlSurrogate))");
Console.WriteLine("Override and surrogate XML are identical.");
private static string TestDefault(List<Person> lPersonList)
Console.WriteLine("\nTesting default serialization for List<Person>: ");
var lSerialiser = new XmlSerializer(lPersonList.GetType());
return TestSerialize(lPersonList, lSerialiser);
static string TestOverride(List<Person> lPersonList)
Console.WriteLine("\nTesting override serialization for List<Person>: ");
var lSerialiser = PersonEmployeeListSerializerFactory.GetSerializer("Employees", "Employee");
return TestSerialize(lPersonList, lSerialiser);
public static string TestSurrogate(List<Person> lPersonList)
Console.WriteLine("\nTesting surrogate serialization for List<Person>: ");
var surrogate = (EmployeesListSurrogate)lPersonList;
var lSerialiser = new XmlSerializer(surrogate.GetType());
return TestSerialize(surrogate, lSerialiser);
private static string TestSerialize<T>(T lPersonList, XmlSerializer lSerialiser)
var lNamespaces = new XmlSerializerNamespaces();
string xml = GetXml(lPersonList, lSerialiser, lNamespaces);
Console.WriteLine("Serialized XML: ");
var list2 = (T)lSerialiser.Deserialize(new StringReader(xml));
string xml2 = GetXml(list2, lSerialiser, lNamespaces);
Console.WriteLine("Deserialized and re-serialized XML: ");
if (!XNode.DeepEquals(XElement.Parse(xml), XElement.Parse(xml2)))
throw new InvalidOperationException("!XNode.DeepEquals(XElement.Parse(xml), XElement.Parse(xml2))");
Console.WriteLine("Original and re-serialized XML are equivalent.");
private static string GetXml<T>(T lPersonList, XmlSerializer lSerialiser, XmlSerializerNamespaces lNamespaces)
var sb = new StringBuilder();
using (var writer = new StringWriter(sb))
lSerialiser.Serialize(writer, lPersonList, lNamespaces);
public static void Main()