Xml deserialization appends to list

元气小坏坏 提交于 2019-12-01 18:13:41

Basically, that's just how XmlSerializer works. Unless the list is null, it never expects to try and set a value. In particular, most of the time, sub-item lists don't have a setter - they are things like:

private readonly List<Child> children = new List<Child>();
public List<Child> Children { get { return children; } }

(because most people don't want external callers to reassign the list; they just want them to change the contents).

Because of this, XmlSerializer operates basically like (over-simplifying):

var list = yourObj.SomeList;
foreach({suitable child found in the data})
    list.Add({new item});

One fix is to use an array rather than a list; it always expects to assign an array back to the object, so for an array it is implemented more like (over-simplifying):

var list = new List<SomeType>();
foreach({suitable child found in the data})
    list.Add({new item});
yourObj.SomeList = list.ToArray();

However, for a fixed number of values, a simpler implementation might be just:

public Foo Value1 {get;set;}
public Foo Value2 {get;set;}
public Foo Value3 {get;set;}

(if you see what I mean)

To get your desired result without changing your data types, you could use a DataContractSerializer (using System.Runtime.Serialization;) instead of the normal XmlSerializer. It doesn't call default constructors therefore you will end up with 3 colours instead of 6.

var ser = new DataContractSerializer(typeof(Settings));
var reader = new FileStream(@"c:\SettingsFile.xml", FileMode.Open);
var deserializedSettings = (Settings)ser.ReadObject(reader);

Coming a bit late to the party, but I just ran into this problem as well.

The accepted answer mentions that Arrays are assigned to every time a deserialization occurs. This was very helpful. But I needed a solution that didn't require me to change the type of the properties and rewrite a million lines of code. So I came up with this:

Using XML Serializer attributes you can 'redirect' the serializer to an Array that wraps around the original property.

[XmlIgnore]
public List<int> AlertColors { get; set; } = new List<int>() { Color.White.ToArgb(), Color.Yellow.ToArgb(), Color.Red.ToArgb() });

[XmlArray(ElementName = "AlertColors")]
public long[] Dummy
{
      get
      {
          return AlertColors.ToArray();
      }
      set
      {
          if(value != null && value.Length > 0) AlertColors = new List<int>(value);
      }
}

The Dummy property has to be public in order for the serializer to access it. For me however this was a small price to pay, leaving the original property unchanged so I didn't have to modify any additional code.

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