7

IXmlSerializable を実装する基本クラスから継承するクラスをシリアル化しようとしています。

PropertyBag と呼ばれる基本クラスは、動的プロパティを許可するクラスです ( Marc Gravell の功績によるものです)。

IXmlSerializable を実装して、動的プロパティ (Dictionary に格納されている) が通常の xml 要素として記述されるようにしました。

たとえば、クラス Person をパブリック プロパティ (非動的) Name と動的プロパティ Age でシリアル化する場合、次の XML を生成したいと考えています。

<Person>
  <Name>Tim</Name>
  <DynamicProperties>
    <Country>
      <string>USA</string>
    </Country>
  </DynamicProperties>
<Person>

基本 PropertyBag クラスの WriteXml の次の実装で動作するパーツを取得できます。

public void WriteXml(System.Xml.XmlWriter writer)
    {
        writer.WriteStartElement("DynamicProperties");

        // serialize every dynamic property and add it to the parent writer
        foreach (KeyValuePair<string, object> kvp in properties)
        {
            writer.WriteStartElement(kvp.Key);

            StringBuilder itemXml = new StringBuilder();
            using (XmlWriter itemWriter = XmlWriter.Create(itemXml))
            {
                // serialize the item
                XmlSerializer xmlSer = new XmlSerializer(kvp.Value.GetType());
                xmlSer.Serialize(itemWriter, kvp.Value);                    

                // read in the serialized xml
                XmlDocument doc = new XmlDocument();
                doc.LoadXml(itemXml.ToString());

                // write to modified content to the parent writer
                writer.WriteRaw(doc.DocumentElement.OuterXml);
            }

            writer.WriteEndElement();
        }

        writer.WriteEndElement();
    }

ただし、Person クラスをシリアル化する場合、Person の WriteXml メソッドを上書きしない限り、通常の (動的ではない) プロパティはシリアル化されなくなります (これはやりたくありません)。基本クラスで静的プロパティを自動的に追加できる方法はありますか? リフレクションを使用して手動でこれを行うことができることは知っていますが、.Net Framework に組み込み機能があるかどうか疑問に思っていましたか?

4

2 に答える 2

3

私はXmlSerializer(および他のさまざまなシリアル化API)にかなりの時間を費やしてきましたが、単純にそうすることはできません。実装IXmlSerializableはすべてか無かです。

私が考えることができる最も近いのは、すべての固定プロパティをチートしてサブオブジェクトに移動することです。これにより、わずかに異なるxmlが得られます-次のようなものです:

<FixedProperties>
   <Name>Tim</Name>
</FixedProperties> 
<DynamicProperties>
  <Country>
    <string>USA</string>
  </Country>
</DynamicProperties>

しかし、私はそれがうまくいくと期待しています。ベースオブジェクトにパススループロパティがあります。

[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public FixedProperties FixedProps {get;set;}
public string Name {
    get {return FixedProps.Name;}
    set {FixedProps.Name = value;}
}

わかる?Nameとしてマークすることもできますが[XmlIgnore]、かなり冗長なようです。特注のシリアル化方法では、使用しますnew XmlSerializer(typeof(FixedProperties))

編集:これが実際の「シリアル化」の例です:

using System;
using System.ComponentModel;
using System.Xml.Serialization;

static class Program
{
    static void Main()
    {
        MyType obj = new MyType { Name = "Fred" };
        var ser = new XmlSerializer(obj.GetType());
        ser.Serialize(Console.Out, obj);
    }
}
public class MyType : IXmlSerializable
{
    public MyType()
    {
        FixedProperties = new MyTypeFixedProperties();
    }
    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
    public MyTypeFixedProperties FixedProperties { get; set; }
    [XmlIgnore]
    public string Name
    {
        get { return FixedProperties.Name; }
        set { FixedProperties.Name = value; }
    }

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

    void IXmlSerializable.ReadXml(System.Xml.XmlReader reader)
    {
        throw new System.NotImplementedException();
    }

    void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer)
    {
        writer.WriteStartElement("DynamicProperties");
        writer.WriteElementString("Foo", "Bar");
        writer.WriteEndElement();
        fixedPropsSerializer.Serialize(writer, FixedProperties);
    }
    static readonly XmlSerializer fixedPropsSerializer
        = new XmlSerializer(typeof(MyTypeFixedProperties));

}
[XmlRoot("FixedProperties")]
public class MyTypeFixedProperties
{
    public string Name { get; set; }
}
于 2009-12-30T22:57:49.633 に答える
1

マーク、FixedProperties を別のコレクションに入れることに関するあなたの答えは、PropertyBag から継承する代わりに、そのタイプのプロパティを作成する必要があると考えさせられました。

そこで、 Person クラスが継承する PropertyBagWrapper クラスを作成しましたが、それは機能します。

[Serializable]
[TypeDescriptionProvider(typeof(PropertyBagDescriptionProvider))]    
public abstract class PropertyBagWrapper
{
    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]    
    public PropertyBag DynamicProperties { get; set; }

    public object this[string name]
    {
        get { return DynamicProperties[name]; }
        set { DynamicProperties[name] = value; }
    }
    protected PropertyBagWrapper()
    {
        DynamicProperties = new PropertyBag(this.GetType());
    }
}

[Serializable]    
public class Person : PropertyBagWrapper
{
    [Browsable(true)]
    public string Name { get; set; }
}

PropertyBag のすべてのコードと ICustomTypeDescriptor の実装に必要なカスタム クラスについては繰り返しませんが、ここで確認できます。

TypeDescriptionProvider 属性を PropertyBag クラスから PropertyBagWrapper クラスに移動しました。

PropertyBag クラスには、質問に投稿された WriteXml() メソッドの同じ実装がまだあります。

于 2009-12-31T00:03:59.683 に答える