locked
How to XML serialize a Generic List<T> containing multiple Types derived from a base class T

    Question

  • I need to serialize to XML a datastructure based on Generics such as List<T>. The problem arises in that I want T to be a base class for multiple derived classes. When I try to serialize this I cannot get the derived classes to be serialized, only the base Class are serialized.

    Eg;

    [Serialize]
    Class Node{
       private string n_info;
    }

    Class Node_A : Node {
       private string a_info;
    }

    Class node_B : Node {
      private string b_info;
    }

    List<Node> list = new List<Node>();
    list.Add(new Node_A());
    list.Add(new Node_B());

     XmlSerializer serializer = new XmlSerializer(typeof(List<Node>),
                        new Type[] { typeof(Node_A), typeof(Node_B) });

    FileStream fstream = new FileStream("ListData.xml", FileMode.Create, FileAccess.Write, FileShare.None);
    serializer.Serialize(fstream, list);
    fstream.Close();

    This runs but only serializes the Node Base Class attributes.

    Wednesday, March 14, 2007 10:12 PM

Answers

  • A bit late maybe, but...have you tried the XmlInclude attribute?
    You need to set an XmlInclude entry on the base class for each subclass. In your example it would be:

    ...
    [Serializable]
    [XmlInclude(Node_A)]
    [XmlInclude(Node_B)]
    Class Node{
       private string n_info;
    }
    ...

    Ugly - yes, but there you go...

    //Carl

    Friday, March 23, 2007 9:31 AM
  • Just a quick point but all your members are marked 'private' and you can only serialize public members with XmlSerializer.  Are you sure that this is not connected to your problem?
    Friday, March 23, 2007 1:18 PM
  • I got it working as follows..

     

    // Create a sample List with test data

    List<Node> list = new List<Node>();

    list.Add(new AppNode("app1"));

    list.Add(new DbNode("db1"));

     

    // Serialise the list

    XmlSerializer serializer = new XmlSerializer(typeof(List<Node>), new Type[] { typeof(AppNode), typeof(DbNode) });

    FileStream fstream = new FileStream("List-Node.xml", FileMode.Create, FileAccess.Write, FileShare.None);

    serializer.Serialize(fstream, list);

    fstream.Close();

     

    // Deserialise the list

    fstream = new FileStream("List-Node.xml.xml", FileMode.Open, FileAccess.Read, FileShare.None);

    list.Clear();

    list = (List<Node>)serializer.Deserialize(fstream);

    fstream.Close();

     

    The Node, AppNode and DBNode are defined as follows:-

     

    [Serializable]

    public class Node

    {

        public Node() {}    // Required for Serialization

     

        public Node(string nm)

        {

            Name = nm;

        }

     

        private string m_name = "";

        public string Name

        {

            get { return m_name; }

            set { m_name = value; }

         }

    }

     

    [Serializable]

    public class AppNode : Node

    {

         public AppNode() : base()  {  }     // Required for Serialization

     

         public AppNode(string nm) : base(nm)

         {

                AppInfo = "Some info about app";

         }

     

         private string m_appInfo;

         public string AppInfo

         {

             get { return m_appInfo; }

             set { m_appInfo = value; }

         }

    }

     

    [Serializable]

    public class DbNode : Node

    {   

        public DbNode() : base()    {}       // Required for Serialization

     

        public DbNode(string nm) : base(nm)

        {

            DbInfo = "Some info about database";

        }

     

        private string m_dbInfo;

        public string DbInfo

        {

            get { return m_dbInfo; }

           set { m_dbInfo = value; }

        }

    }

    Wednesday, March 28, 2007 9:04 AM

All replies

  • A bit late maybe, but...have you tried the XmlInclude attribute?
    You need to set an XmlInclude entry on the base class for each subclass. In your example it would be:

    ...
    [Serializable]
    [XmlInclude(Node_A)]
    [XmlInclude(Node_B)]
    Class Node{
       private string n_info;
    }
    ...

    Ugly - yes, but there you go...

    //Carl

    Friday, March 23, 2007 9:31 AM
  • Just a quick point but all your members are marked 'private' and you can only serialize public members with XmlSerializer.  Are you sure that this is not connected to your problem?
    Friday, March 23, 2007 1:18 PM
  • I got it working as follows..

     

    // Create a sample List with test data

    List<Node> list = new List<Node>();

    list.Add(new AppNode("app1"));

    list.Add(new DbNode("db1"));

     

    // Serialise the list

    XmlSerializer serializer = new XmlSerializer(typeof(List<Node>), new Type[] { typeof(AppNode), typeof(DbNode) });

    FileStream fstream = new FileStream("List-Node.xml", FileMode.Create, FileAccess.Write, FileShare.None);

    serializer.Serialize(fstream, list);

    fstream.Close();

     

    // Deserialise the list

    fstream = new FileStream("List-Node.xml.xml", FileMode.Open, FileAccess.Read, FileShare.None);

    list.Clear();

    list = (List<Node>)serializer.Deserialize(fstream);

    fstream.Close();

     

    The Node, AppNode and DBNode are defined as follows:-

     

    [Serializable]

    public class Node

    {

        public Node() {}    // Required for Serialization

     

        public Node(string nm)

        {

            Name = nm;

        }

     

        private string m_name = "";

        public string Name

        {

            get { return m_name; }

            set { m_name = value; }

         }

    }

     

    [Serializable]

    public class AppNode : Node

    {

         public AppNode() : base()  {  }     // Required for Serialization

     

         public AppNode(string nm) : base(nm)

         {

                AppInfo = "Some info about app";

         }

     

         private string m_appInfo;

         public string AppInfo

         {

             get { return m_appInfo; }

             set { m_appInfo = value; }

         }

    }

     

    [Serializable]

    public class DbNode : Node

    {   

        public DbNode() : base()    {}       // Required for Serialization

     

        public DbNode(string nm) : base(nm)

        {

            DbInfo = "Some info about database";

        }

     

        private string m_dbInfo;

        public string DbInfo

        {

            get { return m_dbInfo; }

           set { m_dbInfo = value; }

        }

    }

    Wednesday, March 28, 2007 9:04 AM