2017-07-19 4 views
1

Ich habe nach Beispielen gesucht, um eine Eigenschaft einer Klasse während der XML-Serialisierung und -Deserialisierung zu ignorieren. Ich habe drei verschiedene Methoden gefunden und kann nicht herausfinden, wann sie verwendet werden sollten. Mein besonderes Interesse gilt dem, der mit XmlSerializer besser arbeitet.Wann ich ShouldSerializeXXX im Vergleich zu XmlIgnoreAttribute für die XML-Serialisierung verwenden musste

  1. XmlIgnore Attribut

    public class Item 
    { 
        [XmlIgnore] 
        public string Name { get; set; } 
    } 
    
  2. beginnend Methode mit ShouldSerialize...

    public class Item 
    { 
        public string Name { get; set; } 
    
        public bool ShouldSerializeName() 
        { 
         return false; 
        } 
    } 
    
  3. NonSerialized Attribut

    public class Item 
    { 
        [NonSerialized] 
        public string Name { get; set; } 
    } 
    

Wo eine Erklärung dort über den Unterschied zwischen XmlIgnoreAttribtue und NonSerializedAttribute auf stackoverflow und msdn ist, war ich nicht in der Lage Informationen zu finden, wenn XmlIgnoreAttribtue und wenn das ShouldSerializeXXX Muster zu verwenden. Ich habe beide mit dem XmlSerializer ausprobiert und beide sehen Arbeit wie erwartet.

+0

Wenn alle nach Ihrem Standard arbeiten, dann wählen Sie die, die Sie bevorzugen. PS Die 'ShouldSerializeXXX' Version ist eine schreckliche Idee, benutze diese nicht! – DavidG

+0

@DavidG: Con bitte Argument, warum ist es eine schreckliche Idee, 'ShouldSerializeXXX' zu verwenden. – scher

+0

Nun, Sie werden Ihr Modell mit all diesen zusätzlichen Methoden verschmutzen, während ein Attribut nicht. – DavidG

Antwort

1

Der grundlegende Unterschied zwischen # 1 und # 2 ist, dass sie unterschiedliche XML Schemas erzeugen. Wenn Sie möchten, dass ein Mitglied aus dem Schema Ihres Typs ausgeschlossen wird, verwenden Sie [XmlIgnore]. Wenn Sie möchten, dass ein Mitglied bedingt hinzugefügt wird, verwenden Sie ShouldSerializeXXX() oder XXXSpecified. (Schließlich wird, wie in this answer angegeben, [NonSerialized] in Option # 3 von XmlSerializer ignoriert.)

Um den Unterschied zwischen # 1 und # 2, sehen Sie xsd.exe verwenden Schemata für Ihre Typen zu generieren. Das folgende Schema wird für die Version # 1 erzeugt und unterlässt vollständig Name Mitglied:

<xs:complexType name="Item" /> 

Während die folgende für die # 2 bedingt umfasst das Name Mitglied:

<xs:sequence> 
    <xs:element minOccurs="0" maxOccurs="1" name="Name" type="xs:string" /> 
</xs:sequence> 

Der Unterschied ergibt sich, weil XmlSerializer und xsd.exe sowohl Führen Sie statische Analyse statt dynamische Code-Analyse. Keines der beiden Tools kann feststellen, dass die Eigenschaft Name im Fall # 2 immer übersprungen wird, da beide Tools den Quellcode für ShouldSerializeName() nicht dekompilieren, um zu beweisen, dass er immer false zurückgibt. Daher wird Name im Schema für Version # 2 erscheinen, obwohl es nie in der Praxis erscheint. Wenn Sie dann einen Webdienst erstellen und Ihr Schema mit WSDL veröffentlichen (oder einfach manuell zur Verfügung stellen), werden für diese beiden Typen unterschiedliche Clients generiert - eines ohne Name Mitglied und eines mit.

Eine zusätzliche Komplexität kann auftreten, wenn die betreffende Eigenschaft einen nicht nullbaren Wertetyp aufweist. Betrachten Sie die folgenden drei Versionen von Item.Zunächst wird eine Version mit einer bedingungslos Wert Eigenschaft enthalten:

public class Item 
{ 
    public int Id { get; set; } 
} 

Erzeugt das folgende Schema mit Id immer vorhanden:

<xs:complexType name="Item"> 
    <xs:sequence> 
     <xs:element minOccurs="1" maxOccurs="1" name="Id" type="xs:int" /> 
    </xs:sequence> 
    </xs:complexType> 

Zweitens eine Version mit einer bedingungslos Wert Eigenschaft ausgeschlossen:

public class Item 
{ 
    [XmlIgnore] 
    public int Id { get; set; } 
} 

Erzeugt das folgende Schema, das die Id-Eigenschaft vollständig ausschließt:

<xs:complexType name="Item" /> 

Und schließlich eine Version mit einer bedingt ausgeschlossen Wert Eigenschaft:

public class Item 
{ 
    public int Id { get; set; } 

    public bool ShouldSerializeId() 
    { 
     return false; 
    } 
} 

Erzeugt das folgende Schema mit Id nur bedingt vorhanden:

<xs:complexType name="Item"> 
    <xs:sequence> 
     <xs:element minOccurs="0" maxOccurs="1" name="Id" type="xs:int" /> 
    </xs:sequence> 
    </xs:complexType> 

Schema # 2 wie erwartet, aber Bekanntmachung Es gibt einen Unterschied zwischen # 1 und # 3: der erste hat während der dritte minOccurs="0" hat. Der Unterschied tritt auf, weil XmlSerializerdocumented ist, um Mitglieder mit null Werten standardmäßig zu überspringen, aber keine ähnliche Logik für nicht nullable Wertelemente hat. Somit wird die Id Eigenschaft in Fall # 1 immer serialisiert, und so wird im Schema angezeigt. Nur wenn die bedingte Serialisierung aktiviert ist, wird minOccurs="0" generiert. Wenn das dritte Schema wiederum ist für die Client-Code-Generierung verwendet wird, eine IdSpecified Eigenschaft wird den automatisch generierten Code hinzugefügt werden, um zu verfolgen, ob die Id Eigenschaft tatsächlich während der Deserialisierung aufgetreten:

public partial class Item { 

    private int idField; 

    private bool idFieldSpecified; 

    /// <remarks/> 
    public int Id { 
     get { 
      return this.idField; 
     } 
     set { 
      this.idField = value; 
     } 
    } 

    /// <remarks/> 
    [System.Xml.Serialization.XmlIgnoreAttribute()] 
    public bool IdSpecified { 
     get { 
      return this.idFieldSpecified; 
     } 
     set { 
      this.idFieldSpecified = value; 
     } 
    } 
} 

Für weitere Einzelheiten über die Bindung an bedingt serialisierte Wertelemente, siehe XML Schema Binding Support: MinOccurs Attribute Binding Support und ShouldSerialize*() vs *Specified Conditional Serialization Pattern.

Also das ist der Hauptunterschied, aber es gibt auch sekundäre Unterschiede, die beeinflussen können, welche Sie sich entscheiden:

  • [XmlIgnore] kann nicht in einer abgeleiteten Klasse überschrieben werden, aber ShouldSerializeXXX() können, wenn sie als virtuelle markiert sein; ein Beispiel finden Sie in here.

  • Wenn ein Mitglied nicht durch XmlSerializer serialisiert werden, da es zum Beispiel auf eine Art bezieht, dass lacks a parameterless constructor, dann markiert das Element mit [XmlIgnore] wird die umschließende Art erlaubt serialisiert werden - während ein ShouldSerializeXXX() { return false; } Zugabe wird das enthält nicht zulassen, Typ zu serialisieren, da wie zuvor erwähnt XmlSerializer nur statische Typanalyse durchführt. Z.B. die folgenden:

    public class RootObject 
    { 
        // This member will prevent RootObject from being serialized by XmlSerializer despite the fact that the ShouldSerialize method always returns false. 
        // To make RootObject serialize successfully, [XmlIgnore] must be added. 
        public NoDefaultConstructor NoDefaultConstructor { get; set; } 
    
        public bool ShouldSerializeNoDefaultConstructor() { return false; } 
    } 
    
    public class NoDefaultConstructor 
    { 
        public string Name { get; set; } 
        public NoDefaultConstructor(string name) { this.Name = name; } 
    } 
    

    nicht durch XmlSerializer serialisiert werden.

  • [XmlIgnore] ist spezifisch für XmlSerializer, aber ShouldSerializeXXX() wird von anderen Serializer einschließlich Json.NET und protobuf-net verwendet.

  • Wie in den Kommentaren erwähnt, wird beim Umbenennen einer bedingt serialisierten Eigenschaft in Visual Studio der entsprechende Methodenname ShouldSerializeXXX() nicht automatisch umbenannt, was zu potenziellen Wartungsfehlern führt.

+1

Vielen Dank für Ihre ausführliche Erklärung. Dies gibt mir eine perfekte Entscheidungshilfe. Groß. – scher

Verwandte Themen