0

我们在 Java 服务器上创建了一个带有“自定义对象和属性”的项目,并且在 C# 客户端上需要这些数据。

例如,自定义对象“A”具有属性“B”、“C”。“B”和“C”都由客户在运行时描述。服务器以 XML 格式将其发送给我们,例如:

<A>
    <B> B Data </B>
    <C> C Data </C>
</A>

我们创建了一个实现IXmlSerializable的类,它读取/写入 xml 以供服务器将自定义属性填充到字典中

public class CustomObject : IXmlSerializable
{
    private Dictionary<String, String> attributes;

    public void ReadXml(XmlReader reader)
    {
        attributes = XDocument.Parse(reader.ReadOuterXml()).Root.Elements()
            .ToDictionary(xElm => xElm.Name.LocalName, xElm => xElm.Value)
    }

    // More Serialization logic for IXmlSerializable is here
}

项目很慢,我们想使用更快的 DataContract 序列化。我们通过在我们的属性(如“B”、“C”)上明确指定硬编码 [DataContract] 来对样本进行测试。然而,在我们的用例中,属性在编译时是未知的。我们可以向服务器查询类型“A”的属性列表。

我们如何将 DataContract 用于运行时定义的属性

4

1 回答 1

1

不支持允许任意未知元素的显式数据协定DataContractSerializerXmlSerializer支持这个 via [XmlAnyElementAttribute],但如答案Using [XmlAnyElement]中所述,数据合同没有相同的功能。

你的班级可以实现IExtensibleDataObject. 它与前向兼容的数据合约类似,[XmlAnyElement]并且旨在用于前向兼容的数据合约。不幸的是,在这种情况下,未知元素存储在不透明ExtensionDataObject的地方,没有明显的方法可以访问这些值。虽然可以从这样的对象中提取 XML(请参见此处),但它并不明显,并且不太可能比您当前的代码具有更高的性能,因为它需要重新序列化ExtensionDataObject包装类内部,然后解析结果。

关于性能的一个注意事项 - 当您这样做时XDocument.Parse(reader.ReadOuterXml())参考源显示您正在有效地解析您的 XML,然后将其通过 a 流式传输XmlWriter到 a StringWriter,然后再次解析生成的字符串。XNode.ReadFrom()您可以通过调用传入的阅读器仅解析一次 XML,而不是这样做,如下所示:

public class CustomObject : IXmlSerializable
{
    private readonly Dictionary<String, String> attributes = new Dictionary<string, string>();

    public IDictionary<string, string> Attributes { get { return attributes; } }

    #region IXmlSerializable Members

    System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema()
    {
        return null;
    }

    void IXmlSerializable.ReadXml(XmlReader reader)
    {
        var element = XElement.ReadFrom(reader) as XElement;
        if (element != null)
        {
            foreach (var item in element.Elements())
                attributes.Add(item.Name.LocalName, (string)item);
        }
    }

    void IXmlSerializable.WriteXml(XmlWriter writer)
    {
        // Do NOT write the wrapper element when writing.
        foreach (var pair in attributes)
        {
            writer.WriteElementString(pair.Key, pair.Value);
        }
    }

    #endregion
}

这应该比您当前的课程更高效。例如,在大型动态 XML 的 Web API 性能问题中,类似优化的报告改进为 40%。

更新

为了实现最佳性能IXmlSerializable,您需要直接从XmlReader使用的定制代码中读取内容。例如,以下将元素名称和值读入attributes字典:

    void IXmlSerializable.ReadXml(XmlReader reader)
    {
        if (reader.IsEmptyElement)
        {
            reader.Read();
            return;
        }
        reader.Read();
        while (reader.NodeType != XmlNodeType.EndElement)
        {
            switch (reader.NodeType)
            {
                case XmlNodeType.Element:
                    var key = reader.Name;
                    var value = reader.ReadElementContentAsString();
                    attributes.Add(key, value);
                    break;

                default:
                    // Comment, for instance.
                    reader.Read();
                    break;
            }
        }
        // Consume the EndElement
        reader.Read();
    }

请参阅实现 IXmlSerializable 的正确方法?有关正确手动读取元素层次结构的一些一般准则。

于 2016-05-26T08:53:46.247 回答