2009-12-30 10 views
7

Próbuję serializować klasę, która dziedziczy z klasy bazowej, która implementuje IXmlSerializable.Jak powrócić do "domyślnej" serializacji XML podczas wdrażania IXmlSerializable w klasie bazowej?

Podstawowa klasa o nazwie PropertyBag jest klasą, która umożliwia właściwości dynamiczne (credits to Marc Gravell).

Zaimplementowałem IXmlSerializable, aby właściwości dynamiczne (przechowywane w słowniku) były zapisywane jako normalne elementy xml.

np. Kiedy szeregowania klasę osoba z mienia publicznego (non dynamicznego) Nazwa i właściwości dynamicznej Age, chciałbym na to, aby generować następujące XML:

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

mogę dostać część do pracy z następującym realizacji z WriteXml w klasie bazowej 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(); 
    } 

jednak, gdy szeregowania klasę Person, to już nie serializes normalne (nie dynamiczny) właściwości, chyba że nadpisać metodę WriteXml osobiście (co nie chcę zrobić). Czy jest jakiś sposób, że w klasie bazowej mogę automatycznie dodać właściwości statyczne? Wiem, że mogę to zrobić ręcznie za pomocą refleksji, ale zastanawiałem się, czy jest jakaś wbudowana funkcjonalność w .Net Framework?

+0

Myślę, że powinieneś unikać słowa "statyczny", ponieważ ma ono inne (bardzo różne) znaczenie ... –

Odpowiedz

1

Marc, odpowiedź na oddanie FixedProperties w kolekcji oddzielnym dało mi do myślenia, że ​​zamiast dziedziczenie z PropertyBag, powinienem utworzyć właściwość tego typu.

Tak więc utworzyłem klasę PropertyBagWrapper, z której dziedziczy moja klasa Osoba i działa.

[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; } 
} 

nie będę powtarzać cały kod dla PropertyBag i niestandardowych klas potrzebnych do realizacji ICustomTypeDescriptor, może się okazać, że here.

Wprowadziłem atrybut TypeDescriptionProvider z klasy PropertyBag do klasy PropertyBagWrapper.

Klasa PropertyBag ma taką samą implementację dla metody WriteXml(), jak opisano w pytaniu.

3

Spędziłem sporo czasu z XmlSerializer (i różnymi innymi API do serializacji) i jestem pewien, że po prostu: nie można. Implementacja IXmlSerializable jest wszystkim lub nic.

Najbliższym, o czym mogę pomyśleć, jest oszukiwanie i przenoszenie wszystkich ustalonych właściwości do pod-obiektu; to dałoby ci nieco inny xml - coś w rodzaju:

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

, ale spodziewam się, że to zadziała. Będziesz miał właściwości pass-thru na swoim obiekcie bazowym:

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

Czy masz sens? Można również oznaczyć Name jako [XmlIgnore], ale wydaje się dość niepotrzebne. W swojej zamówienie metody serializacji byłoby użyć new XmlSerializer(typeof(FixedProperties))

Edycja: Oto praca „serializacji” Przykład:

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

Zaraz na pieniądze. Właśnie dlatego rzeczy DataContract zostały dodane w nowszych wersjach .Net. Dlatego też "stare" usługi internetowe ASMX również dmuchają, ponieważ nie można wykryć serializacji obiektów bez całkowitego napisania serializacji od zera. – jvenema

+0

To powinno zadziałać, ale nie w moim zamierzonym celu. Klasy pochodne już istnieją, chciałem tylko dodać im funkcjonalność właściwości dynamicznych. Ustalone właściwości powinny pozostać w klasie pochodnej. Bardzo doceniam wejście! – Timmel

+0

@jvenema - Czy byłoby to możliwe przy użyciu atrybutów DataContract, a jeśli tak, czy masz jakieś dobre wskazówki dla mnie? – Timmel

Powiązane problemy