Как вернуться назад для 'принятия значение по умолчанию' сериализации XML при реализации IXmlSerializable в базовом классе?

Я пытаюсь сериализировать класс, который наследовался базовому классу, который реализует IXmlSerializable.

Базовый класс, названный PropertyBag, является классом, который позволяет динамические свойства (кредиты Marc Gravell).

Я реализовал IXmlSerializable так, чтобы динамические свойства (сохраненный в Словаре) были записаны как нормальные xml элементы.

например, При сериализации класса Человек с общественной собственностью (не динамичный) Имя и Возраст динамического свойства, я хотел бы за него генерировать следующий XML:


  Tim
  
    
      USA
    
  

Я могу заставить часть работать со следующей реализацией WriteXml в основном классе PropertyBag:

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

        // serialize every dynamic property and add it to the parent writer
        foreach (KeyValuePair 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();
    }

Однако при сериализации класса Человека, это больше не сериализирует нормальное (не динамичный) свойства, если я не перезаписываю метод WriteXml лично (который я не хочу делать). Есть ли какой-либо способ, которым в базовом классе я могу автоматически добавить статические свойства? Я знаю, что могу сделать это вручную отражение использования, но я задавался вопросом, существует ли некоторая встроенная функциональность в.Net Framework?

7
задан Community 23 May 2017 в 10:32
поделиться

2 ответа

Marc, ваш ответ о помещении FixedProperties в отдельную коллекцию заставил меня подумать, что вместо наследования от PropertyBag, я должен создать свойство такого типа.

Поэтому я создал класс PropertyBagWrapper, от которого наследует мой класс Person, и он работает.

[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(), как и в вопросе.

1
ответ дан 7 December 2019 в 14:33
поделиться

Я провел довольно много времени с XmlSerializer (и различными другими API сериализации), и я уверен, что это просто: вы не можете. Реализация IXmlSerializable - это все или ничего.

Ближайшее, что я могу придумать - это обмануть и перенести все исправленные свойства в подобъект; это даст вам немного другой xml - что-то вроде:

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

, но я ожидаю, что это сработает. В вашем базовом объекте у вас будут свойства pass-thru:

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

Имеет ли смысл? Вы также можете пометить Name как [XmlIgnore], но это кажется довольно избыточным. В вашем индивидуальном методе сериализации вы бы использовали новый XmlSerializer(typeof(FixedProperties))

Edit: Вот рабочий пример "сериализации":

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; }
}
3
ответ дан 7 December 2019 в 14:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: