2009-12-30 8 views
7

Ich versuche, eine Klasse zu serialisieren, die von einer Basisklasse erbt, die IXmlSerializable implementiert.Wie wird bei der Implementierung von IXmlSerializable in einer Basisklasse auf die 'Standard' XML-Serialisierung zurückgesetzt?

Die Basisklasse namens PropertyBag ist eine Klasse, die dynamische Eigenschaften zulässt (credits to Marc Gravell).

Ich habe IXmlSerializable implementiert, so dass die dynamischen Eigenschaften (in einem Dictionary gespeichert) als normale XML-Elemente geschrieben werden.

z.B. Wenn eine Klasse Person mit öffentlichem Eigentum (nicht dynamisch) Namen und einer dynamischen Eigenschaft Alten Serialisierung, ich mag für den folgenden XML generieren:

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

ich die Rolle bekommen kann mit der folgenden Umsetzung zu arbeiten von WriteXml in der Basis PropertyBag Klasse:

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(); 
    } 

wenn jedoch die Person Klasse serialisiert, ist es nicht serialisiert mehr den normalen (nicht dynamisch) Eigenschaften, wenn ich die Methode WriteXml in Person (was ich will nicht tun, überschreiben). Gibt es eine Möglichkeit, dass ich in der Basisklasse automatisch die statischen Eigenschaften hinzufügen kann? Ich weiß, dass ich dies manuell über Reflektion tun kann, aber ich habe mich gefragt, ob es eine eingebaute Funktionalität im .Net Framework gibt?

+0

Ich denke, Sie sollten das Wort "statisch" vermeiden, da das eine andere (sehr unterschiedliche) Bedeutung hat ... –

Antwort

1

Marc, Ihre Antwort auf die FixedProperties in einer separaten Sammlung setzen bekam dachte mir, dass statt vererben von PropertyBag sollte ich eine Eigenschaft dieses Typs erstellen.

Also habe ich eine PropertyBagWrapper-Klasse erstellt, die meine Person-Klasse erbt und es funktioniert.

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

Ich werde nicht den gesamten Code für die PropertyBag und die benutzerdefinierten Klassen benötigt für ICustomTypeDescriptor Implementierung wiederholen, können Sie das here finden.

Ich habe das TypeDescriptionProvider-Attribut aus der PropertyBag-Klasse in die PropertyBagWrapper-Klasse verschoben.

Die PropertyBag-Klasse verfügt weiterhin über dieselbe Implementierung für die WriteXml() - Methode wie in der Frage.

3

Ich habe ziemlich viel Zeit mit XmlSerializer (und verschiedenen anderen Serialisierungs-APIs) verbracht, und ich bin mir ziemlich sicher, dass einfach: Sie können nicht. Implementieren IXmlSerializable ist alles oder nichts.

Das nächste, was ich mir vorstellen kann, ist zu betrügen und alle festen Eigenschaften zu einem Unterobjekt zu bewegen; Dies würde Ihnen etwas andere Xml geben - so etwas wie:

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

aber ich erwarte, es würde funktionieren. Sie würden Pass-Thru-Eigenschaften für Ihr Stammobjekt haben:

Sinn machen? Sie könnten auch Name als [XmlIgnore] markieren, aber es scheint ziemlich überflüssig. In Ihrem maßgeschneiderten serialize Methode würden Sie new XmlSerializer(typeof(FixedProperties))

Bearbeiten verwenden: Hier ist ein funktionierendes „serialisiert“ Beispiel:

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

Richtig auf das Geld. Deshalb wurde das DataContract-Zeug in den neueren Versionen von .Net hinzugefügt. Dies ist auch der Grund, warum "alte" asmx-Web-Dienste auch blasen, weil Sie die Serialisierung Ihrer Objekte nicht erkennen können, ohne die Serialisierung komplett neu zu schreiben. – jvenema

+0

Das sollte funktionieren, aber nicht für meinen beabsichtigten Zweck. Die abgeleiteten Klassen existieren bereits, ich wollte ihnen nur Funktionen für dynamische Eigenschaften hinzufügen. Die festen Eigenschaften sollten in der abgeleiteten Klasse verbleiben. Ich schätze den Input sehr! – Timmel

+0

@jvenema - Wäre das mit DataContract-Attributen möglich, und wenn ja, haben Sie gute Anhaltspunkte für mich? – Timmel

Verwandte Themen