Search code examples
c#xml-serializationxmlserializer

XmlSerializer not deserializing XML to IEnumerable


While referencing one of the Stack Overflow posts, XmlSerializer won't serialize IEnumerable, I have the following code that would serialize to XML correctly but when deserialized back, the IEnumerable comes back empty.

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

public class Hello{
    public static void Main(){

        // <!--- Serializing part -->
        Glossary glossary1 = new Glossary();
        glossary1.Term = "Test1";
        glossary1.Definition = "Test1";
        Glossary glossary2 = new Glossary();
        glossary2.Term = "Test2";
        glossary2.Definition = "Test2";
        List<Glossary> glossaryList = new List<Glossary>();
        glossaryList.Add(glossary1);
        glossaryList.Add(glossary2);
        GlossaryCollection glossary = new GlossaryCollection(glossaryList);

        XDocument doc = new XDocument();
        XmlSerializer xmlSerializer = new XmlSerializer(typeof(GlossaryCollection));
        using (var writer = doc.CreateWriter()) {
            xmlSerializer.Serialize(writer, glossary);
        }

        doc.Save("test.xml");
        XDocument doc2 = XDocument.Load("test.xml");
        Console.WriteLine(glossary.glossaryList.Count());
        Console.WriteLine(doc2.ToString());
        //So far looks good - serializing works fine!
        // </!--- Serializing part -->      
        // <!--- De-Serializing part -->                

        GlossaryCollection temp2;
        xmlSerializer = new XmlSerializer(typeof(GlossaryCollection));
        using (var reader = doc2.Root.CreateReader()) {
            var temp = xmlSerializer.Deserialize(reader);
            temp2 = (GlossaryCollection) temp;
        }

        Console.WriteLine(temp2.glossaryList.Count()); // Results in 0, should be 2... :(
        // </!--- De-Serializing part -->               
    }
    [XmlRoot]
            public class GlossaryCollection {
                [XmlIgnore]
                    public IEnumerable<Glossary> glossaryList;
                [XmlElement]    
                    public List<Glossary> GlossarySurrogate { get { return glossaryList.ToList(); } set { glossaryList = value; } }  // https://stackoverflow.com/questions/9102234/xmlserializer-wont-serialize-ienumerable   
                public GlossaryCollection() {
                    glossaryList = new List<Glossary>();
                }
                public GlossaryCollection(IEnumerable<Glossary> glossaryList) {
                    this.glossaryList = glossaryList;
                }
            }
        [XmlType("Glossary")]
                public class Glossary
                {
                        public string Id { get; set; }
                        public string Term { get; set; }
                        public string Definition { get; set; }
                }   
}

Update: Based on Iridium's answer, it does not seem possible to use IEnumerable with XmlSerializer since it was returning a new list everytime, so went with the approach of converting to a List. However if there is a solution (even if hacky) with keeping glossaryList an IEnumerable, do let me know - even if simply for pure curiosity.


Solution

  • When your XML-serialized type has a property of type List<T>, XmlSerializer will get the value of the property, then call .Add(...) to add the deserialized elements (i.e. it does not set the property).

    Since the getter for the GlossarySurrogate property returns a new list every time you get it, the changes the XML serializer makes to the result are lost.

    If you want this to work correctly, you're going to need to convert your glossaryList field to a List<Glossary> and return it directly from the GlossarySurrogate getter, without calling .ToList() on it.