XmlSerializer and List<T> with default values

[亡魂溺海] 提交于 2019-12-21 07:30:31

问题


I observed a weird behavior when serializing and than deserializing a class that is having a member of type List<T> which was filled with default values at construction time. Unlike the array based property the property of type List<T> won't get emptied at deserialization by the XmlSerializer.

Here is my code:

public class Program
{
    public class Config
    {
        public Config()
        {
            Test1 = new List<string>()  {"A", "B"};
            Test2 = new String[] {"A", "B"};
        }
        public List<string> Test1 {get;set;}
        public string[] Test2 {get;set;}
    }

    public static void Main()
    {
        XmlSerializer xmlSerializer =
            new XmlSerializer(typeof(Config));
        using(Stream s = new MemoryStream())
        {
            xmlSerializer.Serialize(s, new Config());
            s.Position = 0;
            xmlSerializer.Serialize(Console.Out,
                xmlSerializer.Deserialize(s));
        }
    }
}

And this is the output:

<?xml version="1.0" encoding="ibm850"?>
<Config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Test1>
    <string>A</string>
    <string>B</string>
    <string>A</string>
    <string>B</string>
  </Test1>
  <Test2>
    <string>A</string>
    <string>B</string>
  </Test2>
</Config>

Why is the List<T> handled differently by XmlSerializer than the array and what can I do to change this behavior?


回答1:


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;
    }
}



回答2:


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();
        }
    }        

}


来源:https://stackoverflow.com/questions/4217139/xmlserializer-and-listt-with-default-values

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!