2009-12-30 1 views
7

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

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

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

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

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

я могу получить часть работать со следующей реализацией не из 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<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, он больше не упорядочивает обычные (не динамические) свойства, если я не перезаписать метод WriteXml в лицо (которое я не хочу делать). Есть ли способ, которым в базовом классе я могу автоматически добавлять статические свойства? Я знаю, что могу сделать это вручную, используя отражение, но мне было интересно, есть ли встроенная функциональность в .NET Framework?

+0

Я думаю, вам следует избегать слова «статические», поскольку это имеет другое (совсем другое) значение ... –

ответ

1

Марк, ваш ответ на ввод в 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, вы можете обнаружить, что here.

Я переместил атрибут TypeDescriptionProvider из класса PropertyBag в класс PropertyBagWrapper.

Класс PropertyBag по-прежнему имеет ту же реализацию для метода WriteXml(), как опубликован в вопросе.

3

Я провел довольно много времени с 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], но он кажется довольно избыточным. В вашем заказе метода сериализации вы будете использовать new 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; } 
} 
+0

Право на деньги. Вот почему материал DataContract был добавлен в более новые версии .Net. Вот почему «старые» веб-службы asmx тоже утомляют, потому что вы не можете обнаружить сериализацию своих объектов, не полностью записывая сериализацию с нуля. – jvenema

+0

Это должно работать, но не по назначению. Производные классы уже существуют, я просто хотел добавить к ним функциональность для динамических свойств. Фиксированные свойства должны оставаться в производном классе. Я очень благодарен за вход! – Timmel

+0

@jvenema - Возможно ли это с использованием атрибутов DataContract, и если да, у вас есть какие-то хорошие указатели для меня? – Timmel