Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 715
Simon D Avatar asked Jul 31 '09 14:07

Simon D


People also ask

What is serializing XML?

XML serialization is the process of converting XML data from its representation in the XQuery and XPath data model, which is the hierarchical format it has in a Db2® database, to the serialized string format that it has in an application.

Can you serialize a list?

A List can be serialized—here we serialize (to a file) a List of objects. Serialize notes. The next time the program runs, we get this List straight from the disk. We see an example of BinaryFormatter and its Serialize methods.

What is serializing and deserializing XML?

Serialization is the process of converting an object into a form that can be readily transported. For example, you can serialize an object and transport it over the Internet using HTTP between a client and a server. On the other end, deserialization reconstructs the object from the stream.

What is the basic difference between SOAP serialization and XML serialization?

XML serialization can also be used to serialize objects into XML streams that conform to the SOAP specification. SOAP is a protocol based on XML, designed specifically to transport procedure calls using XML. To serialize or deserialize objects, use the XmlSerializer class.


2 Answers

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.

like image 175
Damasch Avatar answered Sep 19 '22 17:09

Damasch


See Introducing XML Serialization:

Items That Can Be Serialized

The following items can be serialized using the XmlSerializer class:

  • Public read/write properties and fields of public classes
  • Classes that implement ICollection or IEnumerable
  • XmlElement objects
  • XmlNode objects
  • DataSet objects

In particular, ISerializable or the [Serializable] attribute does not matter.


Now that you've told us what your problem is ("it doesn't work" is not a problem statement), you can get answers to your actual problem, instead of guesses.

When you serialize a collection of a type, but will actually be serializing a collection of instances of derived types, you need to let the serializer know which types you will actually be serializing. This is also true for collections of object.

You need to use the XmlSerializer(Type,Type[]) constructor to give the list of possible types.

like image 43
John Saunders Avatar answered Sep 21 '22 17:09

John Saunders