XmlSerializer and List<T> with default values XmlSerializer and List<T> with default values xml xml

XmlSerializer and List<T> with default values


Interesting; I've never noticed that in the past, but it is definitely reproducible. Since XmlSerializer doesn't support serialization callbacks (to help you know that it is running for serialization) this is hard to influence; arguably the simplest answer is "don't put default data into the objects in the constructor" (although maybe offer a factory method that does that).

You could try implementing IXmlSerializable, but that is overly hard to get right, even for a simple example.

I have checked, though, and DataContractSerializer does not behave this way - so you could perhaps switch to DataContractSerializer; here's my test code with DCS:

DataContractSerializer ser =    new DataContractSerializer(typeof(Config));using (Stream s = new MemoryStream()){    ser.WriteObject(s, new Config());    s.Position = 0;    using(var writer = XmlWriter.Create(Console.Out)) {        ser.WriteObject(writer, ser.ReadObject(s));    }}

and here is what I mean by a the factory method:

public class Config{    public Config()    {        Test1 = new List<string>();        Test2 = nix;    }    public List<string> Test1 { get; set; }    public string[] Test2 { get; set; }    private static readonly string[] nix = new string[0];    public static Config CreateDefault()    {        Config config = new Config();        config.Test1.Add("A");        config.Test1.Add("B");        config.Test2 = new string[2] { "A", "B" };        return config;    }}


This is indeed frustrating behavior of XML deserialization when lists contain a set of default entries created in the constructor.

My workaround was to set the XMLIgnoreAttribute on the List and include a public member of array of the object type with the set/get handling the population of the list from the array.

Something like the following allows for creating defaults in the constructor but keeps the XML serializer from adding entries to the default list. (error/nul validations aside).

public class Config{    public Config()    {        Test1 = new List<string>() { "A", "B" };         Test2 = new String[] { "A", "B" };    }    [XmlIgnore]    public List<string> Test1 { get; set; }    public string[] Test2 { get; set; }    // This member is only to be used during XML serialization    public string[] Test1_Array     {         get        {            return Test1.ToArray();        }        set         {            Test1 = value.ToList();        }    }        }