无法使用XML反序列化器将XML反序列化为列表

这是从我之前的问题继续使用XML序列化序列化接口列表

public class MeterWalkOrder { public MeterWalkOrder() { Meters = new List(); } public String Name { get; set; } [XmlIgnore] public List Meters { get; set; } [XmlArrayItem(ElementName = "Meter")] [XmlArray(ElementName = "Meters")] public List SerializableMeters { get { return Meters.Cast().ToList(); } set { Meters = new List(value); } } } public interface IMeter { int MeterID { get; set; } } public class Meter : IMeter { public int MeterID { get; set; } public string SerialNumber { get; set; } } } 

我正在使用下面的扩展方法将XML反序列化回我的对象​​(理想情况下我更喜欢扩展方法离开对象,但我对扩展方法不太满意所以我现在就这样离开了)…

 public static class SerializationExtensions { public static T LoadFromXML(this string xmlString) { T returnValue = default(T); XmlSerializer serial = new XmlSerializer(typeof(T)); StringReader reader = new StringReader(xmlString); object result = serial.Deserialize(reader); if (result != null && result is T) { returnValue = ((T)result); } reader.Close(); return returnValue; } 

….但是,当我给出下面的XML时……

   Red Route   1 12345   2 SE    

没有电表?

有谁知道什么可能导致这个问题? XML是有效的,SerializeableMeters只是一个读取和写入Meters的属性,但由于在序列化中使用接口的已知问题而将其作为具体类进行转换

问题是XmlSerializer以下列方式反序化一个引用实现IList的类的属性:

  1. 它调用getter来获取列表。 如果为null,则分配一个列表并通过setter设置它。 它在读取时保留在一些局部变量的列表中。

  2. 它反序列化每个列表元素,并将其添加到它所持有的列表中。

  3. 就是这样。 之后它永远不会调用包含类的list属性setter

您可以通过将List替换为ObservableCollection来validation这一点,并在集合更改时设置调试侦听器:

  [XmlArrayItem(ElementName = "Meter")] [XmlArray(ElementName = "Meters")] public ObservableCollection SerializableMeters { get { Debug.WriteLine("Returning proxy SerializableMeters"); var list = new ObservableCollection(Meters.Cast()); list.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(list_CollectionChanged); return list; } set { Debug.WriteLine("Setting proxy SerializableMeters"); Meters = new List(value.Cast()); } } static void list_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { var collection = (IList)sender; Debug.WriteLine("Proxy collection changed to include : "); foreach (var item in collection) Debug.WriteLine(" " + item.ToString()); } 

这样做,您将看到以下调试输出:

 Returning proxy SerializableMeters Returning proxy SerializableMeters Returning proxy SerializableMeters Returning proxy SerializableMeters Proxy collection changed to include : Meter: 1, 12345 Proxy collection changed to include : Meter: 1, 12345 Meter: 2, SE 

如您所见,列表永远不会被撤回。

幸运的是,有一个简单的选择。 如果你返回一个代理数组而不是代理ListXmlSerializer将自己分配数组,填充它,并通过setter设置它 – 这正是你想要的!

  [XmlArrayItem(ElementName = "Meter")] [XmlArray(ElementName = "Meters")] public Meter [] SerializableMeters { get { return Meters.Cast().ToArray(); } set { Meters = new List(value.Cast()); } } 

然后是

  var meters = xml.LoadFromXML(); Debug.Assert(meters.Meters.Count == 2); // No assert.