Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/apache-kafka/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 一种泛型列表反序列化类?_C#_Serialization_Xml Serialization - Fatal编程技术网

C# 一种泛型列表反序列化类?

C# 一种泛型列表反序列化类?,c#,serialization,xml-serialization,C#,Serialization,Xml Serialization,好的,到目前为止的故事是这样的 我已经可以使用XmlSerializer对单个对象进行反序列化,但事实证明,对列表进行反序列化是一件非常头疼的事情。我首先尝试序列化列表,序列化程序序列化根元素中的多个XML结构。事实证明,反序列化是有问题的,所以看起来我需要自己定义“ArrayOfFoo”元素。因此,我有一个类正在工作,它是列表的“包装器”,如本程序所示: using System; using System.IO; using System.Collections.Generic; using

好的,到目前为止的故事是这样的

我已经可以使用
XmlSerializer
对单个对象进行反序列化,但事实证明,对列表进行反序列化是一件非常头疼的事情。我首先尝试序列化
列表
,序列化程序序列化根
元素中的多个
XML结构。事实证明,反序列化是有问题的,所以看起来我需要自己定义“ArrayOfFoo”元素。因此,我有一个类正在工作,它是列表的“包装器”,如本程序所示:

using System;
using System.IO;
using System.Collections.Generic;
using System.Xml.Serialization;

namespace XmlTester2
{
    public class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("XML tester...");

            string xml =
                "<ItemList xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">" +
                "<Person i:type=\"PersonI2\">" + "<Field1>field1Val</Field1>" +
                "<Field2>field2Val</Field2>" + "<Field3>field3Val</Field3>" +
                "<Field4>field4Val</Field4>" + "</Person>" +
                "<Account i:type=\"AccountI2\">" + "<Field1>field1Val</Field1>" +
                "<Field2>field2Val</Field2>" + "<Field3>field3Val</Field3>" +
                "<Field4>field4Val</Field4>" + "</Account>" +
                "<Person i:type=\"PersonI2\">" + "<Field1>field1Val</Field1>" +
                "<Field2>field2Val</Field2>" + "<Field3>field3Val</Field3>" +
                "<Field4>field4Val</Field4>" + "</Person>" + "</ItemList>";

            XmlSerializer ser = new XmlSerializer(typeof(ItemList));

            using (var reader = new StringReader(xml))
            {
                ItemList result = (ItemList)ser.Deserialize(reader);
            }

            Console.WriteLine("Break here and check 'result' in Quickwatch...");
            Console.ReadKey();
        }
    }

    [XmlRootAttribute(IsNullable = false)]
    public class ItemList
    {
        [XmlElementAttribute("Person")]
        public List<Person> Persons { get; set; }

        [XmlElementAttribute("Account")]
        public List<Account> Accounts { get; set; }
    }

    [XmlTypeAttribute(AnonymousType = false, TypeName = "Person", Namespace = "")]
    [XmlInclude(typeof(PersonI2))]
    public class Person
    {
        public string Field1 { get; set; }
        public string Field2 { get; set; }
        public string Field3 { get; set; }
    }

    [XmlTypeAttribute(AnonymousType = false, TypeName = "PersonI2", Namespace = "")]
    public class PersonI2 : Person
    {
        public string Field4 { get; set; }
    }

    [XmlTypeAttribute(AnonymousType = false, TypeName = "Account", Namespace = "")]
    [XmlInclude(typeof(AccountI2))]
    public class Account
    {
        public string Field1 { get; set; }
        public string Field2 { get; set; }
        public string Field3 { get; set; }
    }

    [XmlTypeAttribute(AnonymousType = false, TypeName = "AccountI2", Namespace = "")]
    public class AccountI2 : Account
    {
        public string Field4 { get; set; }
    }
}
因此,在
ItemList
中传递的XML结构只能是一种类型,比如本例中的
Person
,我可以定义一个
ItemList
,允许我反序列化包含多个Person对象的列表?有什么想法吗?如果有必要,我不介意为
ItemList
类标记一个
[xmlclude…]
,用于
ItemList
可能包含的每个类型


我猜这是可能的,我只是还不知道怎么做?:-)还是默认的XmlSerializer太繁琐了?

我不确定我是否理解您的问题,但您知道有一个问题


我不确定我是否理解你的问题,但你知道有一个问题吗

在.NET3.5SP1(具体为SP1)下,您可以使用WCF中的序列化程序来反序列化对象,而无需使用DataContract或可序列化属性对类进行特定标记

几乎任何类都应该能够以这种方式进行反序列化——只要属性名与元素名匹配

如果您遇到反序列化程序错误,则可能是因为某些属性命名错误或类型不正确。要检查序列化程序正在查找的输入,可以填充一次对象,然后将其序列化为XML进行比较

不久前,我为自己编写了一个助手类来使用它

使用辅助对象的方法是:

string serialized = "some xml";
MyType foo = Helpers.Deserialize<MyType>(serialized, SerializerType.Xml); 
string serialized=“some xml”;
MyType foo=Helpers.Deserialize(序列化,SerializerType.Xml);
实际的助手类:

using System.IO;
using System.Runtime.Serialization; // System.Runtime.Serialization.dll (.NET 3.0)
using System.Runtime.Serialization.Json; // System.ServiceModel.Web.dll (.NET 3.5)
using System.Text;
namespace Serialization
{
    public static class Helpers
    {
        /// <summary>
        /// Declare the Serializer Type you want to use.
        /// </summary>
        public enum SerializerType
        {
            Xml, // Use DataContractSerializer
            Json // Use DataContractJsonSerializer
        }

        public static T Deserialize<T>(string SerializedString, SerializerType UseSerializer)
        {
            // Get a Stream representation of the string.
            using (Stream s = new MemoryStream(UTF8Encoding.UTF8.GetBytes(SerializedString)))
            {
                T item;
                switch (UseSerializer)
                {
                    case SerializerType.Json:
                        // Declare Serializer with the Type we're dealing with.
                        var serJson = new DataContractJsonSerializer(typeof(T));
                        // Read(Deserialize) with Serializer and cast
                        item = (T)serJson.ReadObject(s);
                        break;
                    case SerializerType.Xml:
                    default:
                        var serXml = new DataContractSerializer(typeof(T));
                        item = (T)serXml.ReadObject(s);
                        break;
                }
                return item;
            }
        }

        public static string Serialize<T>(T ObjectToSerialize, SerializerType UseSerializer)
        {
            using (MemoryStream serialiserStream = new MemoryStream())
            {
                string serialisedString = null;
                switch (UseSerializer)
                {
                    case SerializerType.Json:
                        // init the Serializer with the Type to Serialize
                        DataContractJsonSerializer serJson = new DataContractJsonSerializer(typeof(T));
                        // The serializer fills the Stream with the Object's Serialized Representation.
                        serJson.WriteObject(serialiserStream, ObjectToSerialize);
                        break;
                    case SerializerType.Xml:
                    default:
                        DataContractSerializer serXml = new DataContractSerializer(typeof(T));
                        serXml.WriteObject(serialiserStream, ObjectToSerialize);
                        break;
                }
                // Rewind the stream to the start so we can now read it.
                serialiserStream.Position = 0;
                using (StreamReader sr = new StreamReader(serialiserStream))
                {
                    // Use the StreamReader to get the serialized text out
                    serialisedString = sr.ReadToEnd();
                    sr.Close();
                }
                return serialisedString;
            }
        }
    }
}
使用System.IO;
使用System.Runtime.Serialization;//System.Runtime.Serialization.dll(.NET 3.0)
使用System.Runtime.Serialization.Json;//System.ServiceModel.Web.dll(.NET 3.5)
使用系统文本;
命名空间序列化
{
公共静态类助手
{
/// 
///声明要使用的序列化程序类型。
/// 
公共枚举序列化类型
{
Xml,//使用DataContractSerializer
Json//使用DataContractJsonSerializer
}
公共静态T反序列化(字符串SerializedString,SerializerType UseSerializer)
{
//获取字符串的流表示形式。
使用(流s=newmemoryStream(UTF8Encoding.UTF8.GetBytes(SerializedString)))
{
T项;
开关(UseSerializer)
{
case SerializerType.Json:
//用我们正在处理的类型声明序列化程序。
var serJson=new DataContractJsonSerializer(typeof(T));
//使用序列化程序和强制转换读取(反序列化)
item=(T)serJson.ReadObject;
打破
case SerializerType.Xml:
违约:
var serXml=新的DataContractSerializer(typeof(T));
item=(T)serXml.ReadObject;
打破
}
退货项目;
}
}
公共静态字符串序列化(T ObjectToSerialize,SerializerType UseSerializer)
{
使用(MemoryStream serialiserStream=new MemoryStream())
{
字符串serialisedString=null;
开关(UseSerializer)
{
case SerializerType.Json:
//使用要序列化的类型初始化序列化程序
DataContractJsonSerializer serJson=新的DataContractJsonSerializer(typeof(T));
//序列化程序用对象的序列化表示形式填充流。
WriteObject(serialiserStream,ObjectToSerialize);
打破
case SerializerType.Xml:
违约:
DataContractSerializer serXml=新的DataContractSerializer(typeof(T));
WriteObject(serialiserStream,ObjectToSerialize);
打破
}
//将流倒回起始位置,以便我们现在可以读取它。
serialiserStream.Position=0;
使用(StreamReader sr=新StreamReader(serialiserStream))
{
//使用StreamReader获取序列化文本
serialisedString=sr.ReadToEnd();
高级关闭();
}
返回序列化字符串;
}
}
}
}
在.NET 3.5 SP1(具体为SP1)下,您可以使用WCF中的序列化程序来反序列化对象,而无需使用DataContract或可序列化属性对类进行特定标记

几乎任何类都应该能够以这种方式进行反序列化——只要属性名与元素名匹配

如果您遇到反序列化程序错误,则可能是因为某些属性命名错误或类型不正确。要检查序列化程序正在查找的输入,可以填充一次对象,然后将其序列化为XML进行比较

不久前,我为自己编写了一个助手类来使用它

使用辅助对象的方法是:

string serialized = "some xml";
MyType foo = Helpers.Deserialize<MyType>(serialized, SerializerType.Xml); 
string serialized=“some xml”;
MyType foo=Helpers.Deserialize(序列化,SerializerType.Xml);

using System.IO; using System.Runtime.Serialization; // System.Runtime.Serialization.dll (.NET 3.0) using System.Runtime.Serialization.Json; // System.ServiceModel.Web.dll (.NET 3.5) using System.Text; namespace Serialization { public static class Helpers { /// <summary> /// Declare the Serializer Type you want to use. /// </summary> public enum SerializerType { Xml, // Use DataContractSerializer Json // Use DataContractJsonSerializer } public static T Deserialize<T>(string SerializedString, SerializerType UseSerializer) { // Get a Stream representation of the string. using (Stream s = new MemoryStream(UTF8Encoding.UTF8.GetBytes(SerializedString))) { T item; switch (UseSerializer) { case SerializerType.Json: // Declare Serializer with the Type we're dealing with. var serJson = new DataContractJsonSerializer(typeof(T)); // Read(Deserialize) with Serializer and cast item = (T)serJson.ReadObject(s); break; case SerializerType.Xml: default: var serXml = new DataContractSerializer(typeof(T)); item = (T)serXml.ReadObject(s); break; } return item; } } public static string Serialize<T>(T ObjectToSerialize, SerializerType UseSerializer) { using (MemoryStream serialiserStream = new MemoryStream()) { string serialisedString = null; switch (UseSerializer) { case SerializerType.Json: // init the Serializer with the Type to Serialize DataContractJsonSerializer serJson = new DataContractJsonSerializer(typeof(T)); // The serializer fills the Stream with the Object's Serialized Representation. serJson.WriteObject(serialiserStream, ObjectToSerialize); break; case SerializerType.Xml: default: DataContractSerializer serXml = new DataContractSerializer(typeof(T)); serXml.WriteObject(serialiserStream, ObjectToSerialize); break; } // Rewind the stream to the start so we can now read it. serialiserStream.Position = 0; using (StreamReader sr = new StreamReader(serialiserStream)) { // Use the StreamReader to get the serialized text out serialisedString = sr.ReadToEnd(); sr.Close(); } return serialisedString; } } } }

[XmlRootAttribute("ItemList", IsNullable = false)]
[XmlInclude(typeof(Person))]
[XmlInclude(typeof(PersonI2))]
[XmlInclude(typeof(Account))]
[XmlInclude(typeof(AccountI2))]
public class ItemList<T> : System.Xml.Serialization.IXmlSerializable
{
    class Map : Dictionary<String, XmlSerializer> 
    { public Map() : base(StringComparer.Ordinal) { } }

    public List<T> Items { get; set; }

    public System.Xml.Schema.XmlSchema GetSchema()
    {
        return null;
    }

    private string TypeName(Type t)
    {
        String typeName = t.Name;
        foreach (XmlTypeAttribute a in t.GetCustomAttributes(typeof(XmlTypeAttribute), true))
            if (!String.IsNullOrEmpty(a.TypeName))
                typeName = a.TypeName;
        return typeName;
    }

    private Map LoadSchema()
    {
        Map map = new Map();
        foreach (XmlIncludeAttribute inc in typeof(ItemList<T>).GetCustomAttributes(typeof(XmlIncludeAttribute), true))
        {
            Type t = inc.Type;
            if (typeof(T).IsAssignableFrom(t))
                map.Add(TypeName(t), new XmlSerializer(t));
        }
        return map;
    }

    public void ReadXml(System.Xml.XmlReader reader)
    {
        Map map = LoadSchema();
        int depth = reader.Depth;

        List<T> items = new List<T>();
        if (!reader.IsEmptyElement && reader.Read())
        {
            while (reader.Depth > depth)
            {
                items.Add((T)map[reader.LocalName].Deserialize(reader));
            }
        }
        this.Items = items;
    }

    public void WriteXml(System.Xml.XmlWriter writer)
    {
        Map map = LoadSchema();
        foreach (T item in this.Items)
        {
            map[TypeName(item.GetType())].Serialize(writer, item);
        }
    }
}
public MyClass { public IMyInterface MyProperty1 { get; set; } public MyBaseType MyProperty2 { get; set; } }
using System;
using System.IO;
using System.Text;
using System.Collections.Generic;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;

namespace XmlTester
{
 public class Program {
  static void Main(string[] args) {
   Console.WriteLine("XML tester...");

// Valid XML for an ItemList of Person's
XmlSerializer ser = new XmlSerializer(typeof(ItemList<Person>));
string xmlIn =
@"<ItemList xmlns:i=""http://www.w3.org/2001/XMLSchema-instance"">
 <PersonBilingual>
  <FullName>John Smith</FullName>
  <Age>21</Age>
  <Language>French</Language>
  <SecondLanguage>German</SecondLanguage>
 </PersonBilingual>
 <Person>
  <FullName>Joe Bloggs</FullName>
  <Age>26</Age>
  <Language>English</Language>
 </Person>
 <Person i:type=""PersonBilingual"">
  <FullName>Jane Doe</FullName>
  <Age>78</Age>
  <Language>Italian</Language>
  <SecondLanguage>English</SecondLanguage>
 </Person>
</ItemList>";

//// Valid XML for an ItemList of Account's
//XmlSerializer ser = new XmlSerializer(typeof(ItemList<Account>));
//string xmlIn =
//@"<ItemList xmlns:i=""http://www.w3.org/2001/XMLSchema-instance"">
// <AccountBank>
//  <AcctName>Deposit account</AcctName>
//  <WithCompany>Bank of Switzerland</WithCompany>
//  <BalanceInEuros>300</BalanceInEuros>
// </AccountBank>
// <Account>
//  <AcctName>Book buying account</AcctName>
//  <WithCompany>Amazon</WithCompany>
// </Account>
// <Account i:type=""AccountBank"">
//  <AcctName>Savings account</AcctName>
//  <WithCompany>Bank of America</WithCompany>
//  <BalanceInEuros>2500</BalanceInEuros>
// </Account>
//</ItemList>";

//// Invalid XML, as we have mixed incompatible types
//XmlSerializer ser = new XmlSerializer(typeof(ItemList<Person>));
//string xmlIn =
//@"<ItemList xmlns:i=""http://www.w3.org/2001/XMLSchema-instance"">
// <PersonBilingual>
//  <FullName>John Smith</FullName>
//  <Age>21</Age>
//  <Language>French</Language>
//  <SecondLanguage>German</SecondLanguage>
// </PersonBilingual>
// <Account>
//  <AcctName>Book buying account</AcctName>
//  <WithCompany>Amazon</WithCompany>
// </Account>
// <Person i:type=""PersonBilingual"">
//  <FullName>Jane Doe</FullName>
//  <Age>78</Age>
//  <Language>Italian</Language>
//  <SecondLanguage>English</SecondLanguage>
// </Person>
//</ItemList>";

   // Deserialize...
   ItemList<Person> result;
   using (var reader = new StringReader(xmlIn)) {
    result = (ItemList<Person>)ser.Deserialize(reader);
   }

   Console.WriteLine("Break here and check 'result' in Quickwatch...");
   Console.ReadKey();

   // Serialize...
   StringBuilder xmlOut = new StringBuilder();
   ser.Serialize(new StringWriter(xmlOut), result);

   Console.WriteLine("Break here and check 'xmlOut' in Quickwatch...");
   Console.ReadKey();
  }
 }

 [XmlRoot(ElementName = "ItemList", IsNullable = false)]
 [XmlInclude(typeof(Person))]
 [XmlInclude(typeof(PersonBilingual))]
 [XmlInclude(typeof(Account))]
 [XmlInclude(typeof(AccountBank))]
 public class ItemList<T> : IXmlSerializable {
  #region Private vars

  /// <summary>
  /// The class that will store our serializers for the various classes that may be (de)serialized, given
  /// the type of this ItemList (ie. the type itself, as well as any type that extends the type)
  /// </summary>
  private class Map : Dictionary<string, XmlSerializer> { public Map() : base(StringComparer.Ordinal) { } }

  #endregion

  #region Private methods

  /// <summary>
  /// Creates a 'schema' for this ItemList, using its type, and the XmlIncludeAttribute types that are
  /// associated with it.  For each XmlIncludeAttribute, if it can be assigned to this ItemList's type (so
  /// it's either the same type as this ItemList's type or a type that extends this ItemList's type), adds
  /// the XmlSerializer for that XmlIncludeAttribute's type to our 'schema' collection, allowing a node
  /// corresponding to that type to be (de)serialized by this ItemList.
  /// </summary>
  /// <returns>The 'schema' containing the XmlSerializer's available for this ItemList to use during (de)serialization.</returns>
  private Map loadSchema() {
   Map map = new Map();
   foreach (XmlIncludeAttribute inc in typeof(ItemList<T>).GetCustomAttributes(typeof(XmlIncludeAttribute), true)) {
    Type t = inc.Type;
    if (typeof(T).IsAssignableFrom(t)) { map.Add(xmlTypeName(t), new XmlSerializer(t)); }
   }
   return map;
  }

  /// <summary>
  /// As the XML type name can be different to our internal class name for that XML type, we need to be able
  /// to expect an XML element name that is different to our internal class name for that XML type.  Hence,
  /// our 'schema' map will contain XmlSerializer's whose keys are based on the XML type name, NOT our
  /// internal class name for that XML type.  This method returns the XML type name given our internal
  /// class we're using to (de)serialize that XML type.  If no XML TypeName is specified in our internal
  /// class's XmlTypeAttribute, we assume an XML type name identical to the internal class name.
  /// </summary>
  /// <param name="t">Our internal class used to (de)serialize an XML type.</param>
  /// <returns>The XML type name corresponding to the given internal class.</returns>
  private string xmlTypeName(Type t) {
   string typeName = t.Name;
   foreach (XmlTypeAttribute ta in t.GetCustomAttributes(typeof(XmlTypeAttribute), true)) {
    if (!string.IsNullOrEmpty(ta.TypeName)) { typeName = ta.TypeName; }
   }
   return typeName;
  }

  #endregion

  #region IXmlSerializable Members

  /// <summary>
  /// Reserved and should not be used.
  /// </summary>
  /// <returns>Must return null.</returns>
  public XmlSchema GetSchema() {
   return null;
  }

  /// <summary>
  /// Generates a list of type T objects from their XML representation; stores them in this.Items.
  /// </summary>
  /// <param name="reader">The System.Xml.XmlReader stream from which the objects are deserialized.</param>
  public void ReadXml(XmlReader reader) {
   Map map = loadSchema();
   int depth = reader.Depth;

   List<T> items = new List<T>();
   if (!reader.IsEmptyElement && reader.Read()) {
    // While the reader is at a greater depth that the initial depth, ie. at one of the elements
    // inside the list wrapper, the initial depth being that of the list wrapper <ItemList>...
    while (reader.Depth > depth) {
     try { items.Add((T)map[reader.LocalName].Deserialize(reader)); }
     catch (InvalidOperationException iopEx) {
      if (
       iopEx.InnerException != null &&
       iopEx.InnerException.Message.StartsWith("The specified type was not recognized")
      ) { throw new InvalidOperationException("Couldn't deserialize node '" + reader.LocalName + "' because although its element node is a valid type, its attribute-specified type was not recognized.  Perhaps it needs adding to the ItemList using XmlIncludeAttribute?", iopEx); }
     }
     catch (KeyNotFoundException knfEx) {
      throw new InvalidOperationException("Couldn't deserialize node '" + reader.LocalName + "' because its element node was not recognized as a valid type.  Perhaps it needs adding to the ItemList using XmlIncludeAttribute?", knfEx);
     }
     catch (Exception ex) {
      throw ex;
     }
    }
   }
   this.Items = items;
  }

  /// <summary>
  /// Converts a list of type T objects into their XML representation; writes them to the specified writer.
  /// </summary>
  /// <param name="writer">The System.Xml.XmlWriter stream to which the objects are serialized.</param>
  public void WriteXml(XmlWriter writer) {
   Map map = loadSchema();
   foreach (T item in this.Items) {
    map[xmlTypeName(item.GetType())].Serialize(writer, item);
   }
  }

  #endregion

  #region Public properties

  public List<T> Items { get; set; }

  #endregion
 }

 /// <summary>
 /// A regular person.
 /// </summary>
 [XmlType(AnonymousType = false, TypeName = "Person", Namespace = "")]
 [XmlInclude(typeof(PersonBilingual))]
 public class Person {
  public string FullName { get; set; }
  public int Age { get; set; }
  public string Language { get; set; }
 }

 /// <summary>
 /// A person who can speak a second language.
 /// </summary>
 [XmlType(AnonymousType = false, TypeName = "PersonBilingual", Namespace = "")]
 public class PersonBilingual : Person {
  public string SecondLanguage { get; set; }
 }

 /// <summary>
 /// Some kind of account.
 /// </summary>
 [XmlType(AnonymousType = false, TypeName = "Account", Namespace = "")]
 [XmlInclude(typeof(AccountBank))]
 public class Account {
  public string AcctName { get; set; }
  public string WithCompany { get; set; }
 }

 /// <summary>
 /// A bank account.
 /// </summary>
 [XmlType(AnonymousType = false, TypeName = "AccountBank", Namespace = "")]
 public class AccountBank : Account {
  public int BalanceInEuros { get; set; }
 }
}
using System;
using System.IO;
using System.Text;
using System.Collections.Generic;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;

namespace XmlTester
{
    public class Program {
        static void Main(string[] args) {
            Console.WriteLine("XML tester...");

// Valid XML for an ItemList of Person's
XmlSerializer ser = new XmlSerializer(typeof(ItemList<Person>));
string xmlIn =
@"<ItemList xmlns:i=""http://www.w3.org/2001/XMLSchema-instance"">
    <PersonBilingual>
        <FullName>John Smith</FullName>
        <Age>21</Age>
        <Language>French</Language>
        <SecondLanguage>German</SecondLanguage>
    </PersonBilingual>
    <Person>
        <FullName>Joe Bloggs</FullName>
        <Age>26</Age>
        <Language>English</Language>
    </Person>
    <Person i:type=""PersonBilingual"">
        <FullName>Jane Doe</FullName>
        <Age>78</Age>
        <Language>Italian</Language>
        <SecondLanguage>English</SecondLanguage>
    </Person>
</ItemList>";

//// Valid XML for an ItemList of Account's
//XmlSerializer ser = new XmlSerializer(typeof(ItemList<Account>));
//string xmlIn =
//@"<ItemList xmlns:i=""http://www.w3.org/2001/XMLSchema-instance"">
//  <AccountBank>
//      <AcctName>Deposit account</AcctName>
//      <WithCompany>Bank of Switzerland</WithCompany>
//      <BalanceInEuros>300</BalanceInEuros>
//  </AccountBank>
//  <Account>
//      <AcctName>Book buying account</AcctName>
//      <WithCompany>Amazon</WithCompany>
//  </Account>
//  <Account i:type=""AccountBank"">
//      <AcctName>Savings account</AcctName>
//      <WithCompany>Bank of America</WithCompany>
//      <BalanceInEuros>2500</BalanceInEuros>
//  </Account>
//</ItemList>";

//// Invalid XML, as we have mixed incompatible types
//XmlSerializer ser = new XmlSerializer(typeof(ItemList<Person>));
//string xmlIn =
//@"<ItemList xmlns:i=""http://www.w3.org/2001/XMLSchema-instance"">
//  <PersonBilingual>
//      <FullName>John Smith</FullName>
//      <Age>21</Age>
//      <Language>French</Language>
//      <SecondLanguage>German</SecondLanguage>
//  </PersonBilingual>
//  <Account>
//      <AcctName>Book buying account</AcctName>
//      <WithCompany>Amazon</WithCompany>
//  </Account>
//  <Person i:type=""PersonBilingual"">
//      <FullName>Jane Doe</FullName>
//      <Age>78</Age>
//      <Language>Italian</Language>
//      <SecondLanguage>English</SecondLanguage>
//  </Person>
//</ItemList>";

            // Deserialize...
            ItemList<Person> result;
            using (var reader = new StringReader(xmlIn)) {
                result = (ItemList<Person>)ser.Deserialize(reader);
            }

            Console.WriteLine("Break here and check 'result' in Quickwatch...");
            Console.ReadKey();

            // Serialize...
            StringBuilder xmlOut = new StringBuilder();
            ser.Serialize(new StringWriter(xmlOut), result);

            Console.WriteLine("Break here and check 'xmlOut' in Quickwatch...");
            Console.ReadKey();
        }
    }

    [XmlRoot(ElementName = "ItemList", IsNullable = false)]
    [XmlInclude(typeof(Person))]
    [XmlInclude(typeof(PersonBilingual))]
    [XmlInclude(typeof(Account))]
    [XmlInclude(typeof(AccountBank))]
    public class ItemList<T> : List<T>, IXmlSerializable {
        #region Private vars

        /// <summary>
        /// The class that will store our serializers for the various classes that may be (de)serialized, given
        /// the type of this ItemList (ie. the type itself, as well as any type that extends the type)
        /// </summary>
        private class Map : Dictionary<string, XmlSerializer> { public Map() : base(StringComparer.Ordinal) { } }

        #endregion

        #region Private methods

        /// <summary>
        /// Creates a 'schema' for this ItemList, using its type, and the XmlIncludeAttribute types that are
        /// associated with it.  For each XmlIncludeAttribute, if it can be assigned to this ItemList's type (so
        /// it's either the same type as this ItemList's type or a type that extends this ItemList's type), adds
        /// the XmlSerializer for that XmlIncludeAttribute's type to our 'schema' collection, allowing a node
        /// corresponding to that type to be (de)serialized by this ItemList.
        /// </summary>
        /// <returns>The 'schema' containing the XmlSerializer's available for this ItemList to use during (de)serialization.</returns>
        private Map loadSchema() {
            Map map = new Map();
            foreach (XmlIncludeAttribute inc in typeof(ItemList<T>).GetCustomAttributes(typeof(XmlIncludeAttribute), true)) {
                Type t = inc.Type;
                if (typeof(T).IsAssignableFrom(t)) { map.Add(xmlTypeName(t), new XmlSerializer(t)); }
            }
            return map;
        }

        /// <summary>
        /// As the XML type name can be different to our internal class name for that XML type, we need to be able
        /// to expect an XML element name that is different to our internal class name for that XML type.  Hence,
        /// our 'schema' map will contain XmlSerializer's whose keys are based on the XML type name, NOT our
        /// internal class name for that XML type.  This method returns the XML type name given our internal
        /// class we're using to (de)serialize that XML type.  If no XML TypeName is specified in our internal
        /// class's XmlTypeAttribute, we assume an XML type name identical to the internal class name.
        /// </summary>
        /// <param name="t">Our internal class used to (de)serialize an XML type.</param>
        /// <returns>The XML type name corresponding to the given internal class.</returns>
        private string xmlTypeName(Type t) {
            string typeName = t.Name;
            foreach (XmlTypeAttribute ta in t.GetCustomAttributes(typeof(XmlTypeAttribute), true)) {
                if (!string.IsNullOrEmpty(ta.TypeName)) { typeName = ta.TypeName; }
            }
            return typeName;
        }

        #endregion

        #region IXmlSerializable Members

        /// <summary>
        /// Reserved and should not be used.
        /// </summary>
        /// <returns>Must return null.</returns>
        public XmlSchema GetSchema() {
            return null;
        }

        /// <summary>
        /// Generates a list of type T objects from their XML representation; stores them in this ItemList.
        /// </summary>
        /// <param name="reader">The System.Xml.XmlReader stream from which the objects are deserialized.</param>
        public void ReadXml(XmlReader reader) {
            Map map = loadSchema();
            int depth = reader.Depth;

            List<T> items = new List<T>();
            if (!reader.IsEmptyElement && reader.Read()) {
                // While the reader is at a greater depth that the initial depth, ie. at one of the elements
                // inside the list wrapper, the initial depth being that of the list wrapper <ItemList>...
                while (reader.Depth > depth) {
                    try { items.Add((T)map[reader.LocalName].Deserialize(reader)); }
                    catch (InvalidOperationException iopEx) {
                        if (
                            iopEx.InnerException != null &&
                            iopEx.InnerException.Message.StartsWith("The specified type was not recognized")
                        ) { throw new InvalidOperationException("Couldn't deserialize node '" + reader.LocalName + "' because although its element node is a valid type, its attribute-specified type was not recognized.  Perhaps it needs adding to the ItemList using XmlIncludeAttribute?", iopEx); }
                    }
                    catch (KeyNotFoundException knfEx) {
                        throw new InvalidOperationException("Couldn't deserialize node '" + reader.LocalName + "' because its element node was not recognized as a valid type.  Perhaps it needs adding to the ItemList using XmlIncludeAttribute?", knfEx);
                    }
                    catch (Exception ex) {
                        throw ex;
                    }
                }
            }
            this.AddRange(items);
        }

        /// <summary>
        /// Converts a list of type T objects into their XML representation; writes them to the specified writer.
        /// </summary>
        /// <param name="writer">The System.Xml.XmlWriter stream to which the objects are serialized.</param>
        public void WriteXml(XmlWriter writer) {
            Map map = loadSchema();
            foreach (T item in this) {
                map[xmlTypeName(item.GetType())].Serialize(writer, item);
            }
        }

        #endregion
    }

    /// <summary>
    /// A regular person.
    /// </summary>
    [XmlType(AnonymousType = false, TypeName = "Person", Namespace = "")]
    [XmlInclude(typeof(PersonBilingual))]
    public class Person {
        public string FullName { get; set; }
        public int Age { get; set; }
        public string Language { get; set; }
    }

    /// <summary>
    /// A person who can speak a second language.
    /// </summary>
    [XmlType(AnonymousType = false, TypeName = "PersonBilingual", Namespace = "")]
    public class PersonBilingual : Person {
        public string SecondLanguage { get; set; }
    }

    /// <summary>
    /// Some kind of account.
    /// </summary>
    [XmlType(AnonymousType = false, TypeName = "Account", Namespace = "")]
    [XmlInclude(typeof(AccountBank))]
    public class Account {
        public string AcctName { get; set; }
        public string WithCompany { get; set; }
    }

    /// <summary>
    /// A bank account.
    /// </summary>
    [XmlType(AnonymousType = false, TypeName = "AccountBank", Namespace = "")]
    public class AccountBank : Account {
        public int BalanceInEuros { get; set; }
    }
}