1

在我的一个对象中,我有一个字典,它通过实现进行序列化IXmlSerializable

    public SerializableStringDictionary Parameters { get; set; }

当我使用普通的 .NET 序列化程序序列化这些对象的列表时,它可以很好地序列化,但是反序列化只执行一个对象——XML 文件中遵循可序列化字典的元素被跳过。

例如,我有一个<MaintenanceIndicators>. 我在下面只显示一个,但这是List<MaintenanceIndicator>代码中的一个。具有多个条目的列表的序列化工作正常,但反序列化多个只给我MaintenanceIndicator列表中的 1。但是,它的参数属性可以反序列化。代码中不会抛出异常。

我使用以下代码进行反序列化:

    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>
4

2 回答 2

2

您的问题不包含您的问题的完整示例。为了确认,您有以下(简化的)类定义,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>

在这种情况下,使用 your ReadXml(),我能够重现,在阅读上面的解析时,只有第一个<MaintenanceIndicator>元素被反序列化。

您的问题是,在 中ReadXml(),您不使用</Parameters>端节点。从文档

当此方法返回时,它必须从头到尾读取整个元素,包括其所有内容。与 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)

于 2015-12-22T21:22:48.773 回答
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);
    }

让我知道这种序列化在您的场景中是否可以接受

于 2015-12-21T23:48:15.573 回答