无法使用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
的类的属性:
-
它调用getter来获取列表。 如果为null,则分配一个列表并通过setter设置它。 它在读取时保留在一些局部变量的列表中。
-
它反序列化每个列表元素,并将其添加到它所持有的列表中。
-
就是这样。 之后它永远不会调用包含类的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
如您所见,列表永远不会被撤回。
幸运的是,有一个简单的选择。 如果你返回一个代理数组而不是代理List , XmlSerializer
将自己分配数组,填充它,并通过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.