在我的一个对象中,我有一个通过实现IXmlSerializable
序列化的字典:
public SerializableStringDictionary Parameters { get; set; }
当我使用普通的.NET序列化程序序列化这些对象的列表时,它序列化很好,但是反序列化只执行单个对象 - XML文件中跟随可序列化字典的元素被跳过。
例如,我有一个<MaintenanceIndicators>
列表。我只在下面显示一个,但这是代码中的List<MaintenanceIndicator>
。具有多个条目的列表的序列化工作正常,但反序列化多个仅在列表中给出1 MaintenanceIndicator
。然而,它的参数属性被反序列化了。代码中没有抛出异常。
我使用以下代码进行反序列化:
public void ReadXml(XmlReader reader)
{
bool wasEmpty = reader.IsEmptyElement;
// jump to <parameters>
reader.Read();
if (wasEmpty)
return;
// read until we reach the last element
while (reader.NodeType != System.Xml.XmlNodeType.EndElement)
{
// jump to <item>
reader.MoveToContent();
// jump to key attribute and read
reader.MoveToAttribute("key");
string key = reader.GetAttribute("key");
// jump to value attribute and read
reader.MoveToAttribute("value");
string value = reader.GetAttribute("value");
// add item to the dictionary
this.Add(key, value);
// jump to next <item>
reader.ReadStartElement("item");
reader.MoveToContent(); // workaround to trigger node type
}
}
我在XML中的结构如下所示:
<MaintenanceIndicators>
<MaintenanceIndicator Id="1" Name="Test" Description="Test" Type="LimitMonitor" ExecutionOrder="1">
<Parameters>
<item key="Input" value="a" />
<item key="Output" value="b" />
<item key="Direction" value="GreaterThan" />
<item key="LimitValue" value="1" />
<item key="Hysteresis" value="1" />
</Parameters>
</MaintenanceIndicator>
<!-- Any subsequent MaintenanceIndicator indicator element will not be read -->
</MaintenanceIndicators>
答案 0 :(得分:2)
您的问题并不包含问题的complete示例。要确认,您有以下(简化)类定义,问题中显示SerializableStringDictionary
:
public class MaintenanceIndicator
{
public MaintenanceIndicator()
{
this.Parameters = new SerializableStringDictionary();
}
public SerializableStringDictionary Parameters { get; set; }
}
[XmlRoot("MaintenanceIndicators")]
public class MaintenanceIndicators
{
[XmlElement("MaintenanceIndicator")]
public List<MaintenanceIndicator> MaintenanceIndicatorList { get; set; }
}
以下XML:
<MaintenanceIndicators> <MaintenanceIndicator> <Parameters> <item key="Input" value="a" /> <item key="Output" value="b" /> </Parameters> </MaintenanceIndicator> <MaintenanceIndicator> <Parameters> <item key="Input2" value="a" /> <item key="Output2" value="b" /> </Parameters> </MaintenanceIndicator> </MaintenanceIndicators>
在这种情况下,使用您的ReadXml()
,我能够重现,在阅读上面的解析时,只反序列化了第一个<MaintenanceIndicator>
元素。
您的问题是,在ReadXml()
中,您不会使用</Parameters>
结束节点。来自docs:
当此方法返回时,它必须从头到尾读取整个元素,包括其所有内容。与WriteXml方法不同,框架不会自动处理包装元素。您的实施必须这样做。如果不遵守这些定位规则,可能会导致代码生成意外的运行时异常或损坏数据。
未能在reader.Read();
结束时调用ReadXml()
来读取元素结尾将导致XML中的所有后续元素被跳过或以其他方式被错误地读取。
因此,您应该按如下方式修改ReadXml()
:
public void ReadXml(XmlReader reader)
{
bool wasEmpty = reader.IsEmptyElement;
// jump to <parameters>
reader.Read();
if (wasEmpty)
return;
// read until we reach the last element
while (reader.NodeType != System.Xml.XmlNodeType.EndElement)
{
// jump to <item>
reader.MoveToContent();
// jump to key attribute and read
string key = reader.GetAttribute("key");
// jump to value attribute and read
string value = reader.GetAttribute("value");
// add item to the dictionary
this.Add(key, value);
// jump to next <item>
reader.ReadStartElement("item");
reader.MoveToContent(); // workaround to trigger node type
}
// Consume the </Parameters> node as required by the documentation
// https://msdn.microsoft.com/en-us/library/system.xml.serialization.ixmlserializable.readxml%28v=vs.110%29.aspx
// Unlike the WriteXml method, the framework does not handle the wrapper element automatically. Your implementation must do so.
reader.Read();
}
请注意,在致电reader.MoveToAttribute(string name)
之前无需致电reader.GetAttribute(string name)
。
答案 1 :(得分:0)
如果你需要使用低类型对象(因为字典可能出现),使用javascript序列化器而不是XML更灵活。
例如:
private void button1_Click(object sender, EventArgs e)
{
List<Dictionary<string, string>> datas = new List<Dictionary<string, string>>();
Dictionary<string,string> d1 = new Dictionary<string,string> ();
d1.Add ( "key11","value11");
d1.Add ( "key12","value12");
Dictionary<string,string> d2 = new Dictionary<string,string> ();
d2.Add ( "key21","value21");
d2.Add ( "key22","value22");
datas.Add(d1);
datas.Add(d2);
JavaScriptSerializer serializer = new JavaScriptSerializer();
string serialized = serializer.Serialize (datas);
List<Dictionary<string, string>> deserialized = serializer.Deserialize<List<Dictionary<string, string>>>(serialized);
}
让我知道你的情景中是否可以接受这种可能性