Xml反序列化附加到列表中

我正在尝试从xml文件反序列化一些设置。 有问题的属性/底层字段是一个名为AlertColors字段。 我将基础字段初始化为白色,黄色和红色,以确保此类的新实例具有有效的颜色设置。 但是当我反序列化时, _colorArgb以六个值结束,前三个是初始化值,后三个是从xml文件中读取的值。 但属性AlertColors不会附加到该字段,但会更改其元素。 为什么我最终得到六种颜色的场?

这是代码:

  private List _colorArgb = new List(new int[] { Color.White.ToArgb(), Color.Yellow.ToArgb(), Color.Red.ToArgb() }); public List AlertColors { get { return _colorArgb; } set { for (int i = 0; i < Math.Min(_colorArgb.Count, value.Count); i++) { if (_colorArgb[i] != value[i]) { HasChanged = true; } } _colorArgb = value; } } public bool Deserialize(string filePath) { if (!File.Exists(filePath)) { Logger.Log("Error while loading the settings. File does not exist."); return false; } FileStream fileStream = null; try { fileStream = new FileStream(filePath, FileMode.Open); System.Xml.Serialization.XmlSerializerFactory xmlSerializerFactory = new XmlSerializerFactory(); System.Xml.Serialization.XmlSerializer xmlSerializer = xmlSerializerFactory.CreateSerializer(typeof(Settings)); Settings deserializedSettings = (Settings)xmlSerializer.Deserialize(fileStream); GetSettings(deserializedSettings); Logger.Log("Settings have been loaded successfully from the file " + filePath); } catch (IOException iOException) { Logger.Log("Error while loading the settings. " + iOException.Message); return false; } catch (ArgumentException argumentException) { Logger.Log("Error while loading the settings. " + argumentException.Message); return false; } catch (InvalidOperationException invalidOperationException) { Logger.Log("Error while loading the settings. Settings file is not supported." + invalidOperationException.Message); return false; } finally { if (fileStream != null) fileStream.Close(); FilePath = filePath; } return true; } protected void GetSettings(Settings settings) { AlertColors = settings.AlertColors; } 

以及我要反序列化的xml文件的相关部分:

   -1 -15 -65536  

基本上,这就是XmlSerializer工作原理。 除非列表为null ,否则它永远不会尝试设置值。 特别是, 大多数情况下,子项列表没有 setter – 它们是这样的:

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

(因为大多数人不希望外部呼叫者重新分配列表;他们只是希望他们更改内容)。

因此, XmlSerializer基本上就像(过度简化):

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

一个解决方法是使用数组而不是列表; 它总是希望将一个数组分配给该对象,因此对于一个数组,它实现更像(过度简化):

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

但是,对于固定数量的值,更简单的实现可能只是:

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

(如果你明白我的意思)

要在不更改数据类型的情况下获得所需结果,可以使用DataContractSerializer(使用System.Runtime.Serialization;)而不是普通的XmlSerializer。 它不会调用默认构造函数,因此最终会使用3种颜色而不是6种颜色。

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

派对迟到了,但我也遇到了这个问题。

接受的答案提到每次反序列化时都会分配数组。 这非常有帮助。 但是我需要一个解决方案,它不需要我改变属性的类型并重写一百万行代码。 所以我想出了这个:

使用XML Serializer属性,您可以将序列化程序“重定向”到包含原始属性的Array。

 [XmlIgnore] public List AlertColors { get; set; } = new List() { 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(value); } } 

Dummy属性必须是公共的,以便序列化程序访问它。 对我来说,这是一个很小的代价,原来的属性保持不变,所以我没有必要修改任何额外的代码。