0

Java サーバーで作成された「カスタム オブジェクトと属性」を含むプロジェクトがあり、C# クライアントでこのデータが必要です。

たとえば、カスタムオブジェクト「A」には属性「B」、「C」があります。'B' と 'C' の両方が実行時に顧客によって記述されます。サーバーはこれを次のような XML で送信します。

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

カスタム属性をディクショナリに入力するサーバーの xml を読み書きするIXmlSerializableを実装するクラスを作成しました。

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 Serialization を使用したいと考えています。属性 (「B」、「C」など) にハードコードされた [DataContract] を明示的に指定して、サンプルでテストしました。ただし、私たちのユースケースでは、属性はコンパイル時にわかりません。タイプ「A」の属性のリストをサーバーに照会できます。

実行時に定義された属性に DataContract を使用するにはどうすればよいですか

4

1 に答える 1

1

では、任意の不明な要素を許可する明示的なデータ コントラクトはサポートされていませんDataContractSerializerXmlSerializerを介してこれをサポートします[XmlAnyElementAttribute]が、回答Using [XmlAnyElement]で述べたように、データ コントラクトには同一の機能はありません。

あなたのクラスは を実装できますIExtensibleDataObjectこれは、前方互換性のあるデータ コントラクトに似て[XmlAnyElement]おり、それを対象としています。残念ながら、その場合、不明な要素は不透明に格納され、値にアクセスする明白な方法はありません。このようなオブジェクトから XML を抽出することは可能ですが (こちらを参照) 、ラッパー クラス内で を再シリアル化し、結果を解析する必要があるため、自明ではなく、現在のコードよりもパフォーマンスが向上する可能性は低いです。ExtensionDataObjectExtensionDataObject

パフォーマンスに関する 1 つの注意事項 - を実行するXDocument.Parse(reader.ReadOuterXml())と、リファレンス ソースは、XML を効果的に解析し、 を介して にストリーミングしXmlWriterStringWriter結果の文字列をもう一度解析していることを示しています。XNode.ReadFrom()これを行う代わりに、次のように受信リーダーを呼び出すことで、XML を 1 回だけ解析できます。

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 に答える