Search code examples
c#listgenericsxml-serialization

XML Serialize generic list of serializable objects


Can I serialize a generic list of serializable objects without having to specify their type.

Something like the intention behind the broken code below:

List<ISerializable> serializableList = new List<ISerializable>();

XmlSerializer xmlSerializer = new XmlSerializer(serializableList.GetType());

serializableList.Add((ISerializable)PersonList);

using (StreamWriter streamWriter = System.IO.File.CreateText(fileName))
{
    xmlSerializer.Serialize(streamWriter, serializableList);
}

Edit:

For those who wanted to know detail: when I try to run this code, it errors on the XMLSerializer[...] line with:

Cannot serialize interface System.Runtime.Serialization.ISerializable.

If I change to List<object> I get "There was an error generating the XML document.". The InnerException detail is "{"The type System.Collections.Generic.List1[[Project1.Person, ConsoleFramework, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]] may not be used in this context."}"

The person object is defined as follows:

[XmlRoot("Person")]
public class Person
{
    string _firstName = String.Empty;
    string _lastName = String.Empty;

    private Person()
    {
    }

    public Person(string lastName, string firstName)
    {
        _lastName = lastName;
        _firstName = firstName;
    }

    [XmlAttribute(DataType = "string", AttributeName = "LastName")]
    public string LastName
    {
        get { return _lastName; }
        set { _lastName = value; }
    }

    [XmlAttribute(DataType = "string", AttributeName = "FirstName")]
    public string FirstName
    {
        get { return _firstName; }
        set { _firstName = value; }
    }
}

The PersonList is just a List<Person> .

This is just for testing though, so didn't feel the details were too important. The key is I have one or more different objects, all of which are serializable. I want to serialize them all to one file. I thought the easiest way to do that would be to put them in a generic list and serialize the list in one go. But this doesn't work.

I tried with List<IXmlSerializable> as well, but that fails with

System.Xml.Serialization.IXmlSerializable cannot be serialized because it does not have a parameterless constructor.

Sorry for the lack of detail, but I am a beginner at this and don't know what detail is required. It would be helpful if people asking for more detail tried to respond in a way that would leave me understanding what details are required, or a basic answer outlining possible directions.

Also thanks to the two answers I've got so far - I could have spent a lot more time reading without getting these ideas. It's amazing how helpful people are on this site.


Solution

  • I have an solution for a generic List<> with dynamic binded items.

    class PersonalList it's the root element

    [XmlRoot("PersonenListe")]
    [XmlInclude(typeof(Person))] // include type class Person
    public class PersonalList
    {
        [XmlArray("PersonenArray")]
        [XmlArrayItem("PersonObjekt")]
        public List<Person> Persons = new List<Person>();
    
        [XmlElement("Listname")]
        public string Listname { get; set; }
    
        // Konstruktoren 
        public PersonalList() { }
    
        public PersonalList(string name)
        {
            this.Listname = name;
        }
    
        public void AddPerson(Person person)
        {
            Persons.Add(person);
        }
    }
    

    class Person it's an single list element

    [XmlType("Person")] // define Type
    [XmlInclude(typeof(SpecialPerson)), XmlInclude(typeof(SuperPerson))]  
            // include type class SpecialPerson and class SuperPerson
    public class Person
    {
        [XmlAttribute("PersID", DataType = "string")]
        public string ID { get; set; }
    
        [XmlElement("Name")]
        public string Name { get; set; }
    
        [XmlElement("City")]
        public string City { get; set; }
    
        [XmlElement("Age")]
        public int Age { get; set; }
    
        // Konstruktoren 
        public Person() { }
    
        public Person(string name, string city, int age, string id)
        {
            this.Name = name;
            this.City = city;
            this.Age = age;
            this.ID = id;
        }
    }
    

    class SpecialPerson inherits Person

    [XmlType("SpecialPerson")] // define Type
    public class SpecialPerson : Person
    {
        [XmlElement("SpecialInterests")]
        public string Interests { get; set; }
    
        public SpecialPerson() { }
    
        public SpecialPerson(string name, string city, int age, string id, string interests)
        {
            this.Name = name;
            this.City = city;
            this.Age = age;
            this.ID = id;
            this.Interests = interests;
        }
    }
    

    class SuperPerson inherits Person

    [XmlType("SuperPerson")] // define Type
    public class SuperPerson : Person
    {
        [XmlArray("Skills")]
        [XmlArrayItem("Skill")]
        public List<String> Skills { get; set; }
    
        [XmlElement("Alias")]
        public string Alias { get; set; }
    
        public SuperPerson() 
        {
            Skills = new List<String>();
        }
    
        public SuperPerson(string name, string city, int age, string id, string[] skills, string alias)
        {
            Skills = new List<String>();
    
            this.Name = name;
            this.City = city;
            this.Age = age;
            this.ID = id;
            foreach (string item in skills)
            {
                this.Skills.Add(item);   
            }
            this.Alias = alias;
        }
    }
    

    and the main test Source

    static void Main(string[] args)
    {
        PersonalList personen = new PersonalList(); 
        personen.Listname = "Friends";
    
        // normal person
        Person normPerson = new Person();
        normPerson.ID = "0";
        normPerson.Name = "Max Man";
        normPerson.City = "Capitol City";
        normPerson.Age = 33;
    
        // special person
        SpecialPerson specPerson = new SpecialPerson();
        specPerson.ID = "1";
        specPerson.Name = "Albert Einstein";
        specPerson.City = "Ulm";
        specPerson.Age = 36;
        specPerson.Interests = "Physics";
    
        // super person
        SuperPerson supPerson = new SuperPerson();
        supPerson.ID = "2";
        supPerson.Name = "Superman";
        supPerson.Alias = "Clark Kent";
        supPerson.City = "Metropolis";
        supPerson.Age = int.MaxValue;
        supPerson.Skills.Add("fly");
        supPerson.Skills.Add("strong");
    
        // Add Persons
        personen.AddPerson(normPerson);
        personen.AddPerson(specPerson);
        personen.AddPerson(supPerson);
    
        // Serialize 
        Type[] personTypes = { typeof(Person), typeof(SpecialPerson), typeof(SuperPerson) };
        XmlSerializer serializer = new XmlSerializer(typeof(PersonalList), personTypes); 
        FileStream fs = new FileStream("Personenliste.xml", FileMode.Create); 
        serializer.Serialize(fs, personen); 
        fs.Close(); 
        personen = null;
    
        // Deserialize 
        fs = new FileStream("Personenliste.xml", FileMode.Open); 
        personen = (PersonalList)serializer.Deserialize(fs); 
        serializer.Serialize(Console.Out, personen);
        Console.ReadLine();
    }
    

    Important is the definition and includes of the diffrent types.