这是我之前提出的问题Serialize list of interfaces using XML Serialization
public class MeterWalkOrder
{
public MeterWalkOrder()
{
Meters = new List<IMeter>();
}
public String Name { get; set; }
[XmlIgnore]
public List<IMeter> Meters { get; set; }
[XmlArrayItem(ElementName = "Meter")]
[XmlArray(ElementName = "Meters")]
public List<Meter> SerializableMeters
{
get
{
return Meters.Cast<Meter>().ToList();
}
set
{
Meters = new List<IMeter>(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<T>(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时....
<?xml version="1.0"?>
<MeterWalkOrder xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>Red Route</Name>
<Meters>
<Meter>
<MeterID>1</MeterID>
<SerialNumber>12345</SerialNumber>
</Meter>
<Meter>
<MeterID>2</MeterID>
<SerialNumber>SE</SerialNumber>
</Meter>
</Meters>
</MeterWalkOrder>
没有填充米?
有谁知道什么可能导致这个问题? XML是有效的,SerializeableMeters只是一个读取和写入Meters的属性,但由于在序列化中使用接口的已知问题而将其作为具体类进行编译
答案 0 :(得分:0)
问题是XmlSerializer
以下列方式反序引用一个实现IList<T>
的类的属性:
它调用getter获取列表。如果为null,则分配一个列表并通过setter设置它。它在阅读时保留在一些局部变量的列表中。
它反序列化每个列表元素,并将其添加到它所持有的列表中。
就是这样。之后它永远不会调用包含类的 list属性setter 。
您可以通过将List<Meter>
替换为ObservableCollection<Meter>
并在集合更改时设置调试侦听器来验证这一点:
[XmlArrayItem(ElementName = "Meter")]
[XmlArray(ElementName = "Meters")]
public ObservableCollection<Meter> SerializableMeters
{
get
{
Debug.WriteLine("Returning proxy SerializableMeters");
var list = new ObservableCollection<Meter>(Meters.Cast<Meter>());
list.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(list_CollectionChanged);
return list;
}
set
{
Debug.WriteLine("Setting proxy SerializableMeters");
Meters = new List<IMeter>(value.Cast<IMeter>());
}
}
static void list_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
var collection = (IList<Meter>)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<Meter>().ToArray();
}
set
{
Meters = new List<IMeter>(value.Cast<IMeter>());
}
}
然后是
var meters = xml.LoadFromXML<MeterWalkOrder>();
Debug.Assert(meters.Meters.Count == 2); // No assert.