2016-05-22 3 views
1
<Customer> 
<FirstName>SomeValue</FirstName> 
<LastName>Somevalue</LastName> 
<Address/> 
</Customer> 

Ich habe die oben genannten XML, Adress-Element ist ein komplexes Objekt. Wenn ich versuche, das C# -Objekt zu deserialisieren, werden alle Eigenschaften im Adressobjekt auf null gesetzt, aber ich muss das Adressobjekt selbst auf null setzen. Gibt es einen Weg, dies zu erreichen?Wie kann ich ein komplexes XML-Element ohne Werte auf Null deserialisieren?

+0

Können Sie die C# für Ihre "Kunden" - und "Adress" -Klassen teilen? – dbc

+1

Bitte a [mcve] einbeziehen. –

Antwort

-1

Sie können das XmlIgnore Attribut eine Eigenschaft Ihrer Objekte auszuschließen

[XmlIgnore] 
public Address {get; set;} 
2

Um Ihre Frage zu bestätigen, Sie fragen: Wenn XML deserialisieren, kann ich ein leeres Element zu einer null Eigenschaft Karte Wert, aber ordnen Sie ein nicht leeres Element einem Nicht-null Eigenschaftswert zu?

Angenommen, Sie verwenden XmlSerializer, ist dies nicht out of the Box implementiert. XmlSerializer ordnet ein Element nur dann einem null-Wert zu, wenn das Attribut {http://www.w3.org/2001/XMLSchema}nil, normalerweise abgekürzt xsi:nil, den Wert "true" hat. Von Xsi:nil Attribute Binding Support:

Die XmlSerializer-Klasse entspricht einen wahren Wert für das nil Attribut mit einer Null-Referenz, die folgenden Laufzeitkonvertierungen durchführen:

  • Wenn ein XML-Dokument in Objekte Deserialisieren: Wenn Die XmlSerializer-Klasse erkennt ein XML-Element, das xsi angibt: nil = "true", weist dem entsprechenden Objekt eine Nullreferenz zu (falls zutreffend).
  • Beim Serialisieren von Objekten in ein XML-Dokument: Wenn die XmlSerializer-Klasse einen NULL-Verweis für ein einem XML-Element entsprechendes Objekt vorfindet, generiert sie entweder ein Element, das xsi angibt: nil = "true" oder verlässt das Element vollständig ob eine nillable = "true" Einstellung gilt.

Da xsi:nil ist er nicht in Ihrem leeren <Address> Element, wird es nicht automatisch zu null abgebildet bekommen.

Als Abhilfe kann, könnten Sie eine zusätzliche „Proxy“ Eigenschaft für Address in Customer einzuführen, die während der Deserialisierung überprüft, ob das Address sein Set Standardwerte hat, und wenn ja, setzt der zugrunde liegende Adressenwert null. Zum Beispiel, wenn Ihre Klassen wie folgt aussehen:

public class Address 
{ 
    public string Street1 { get; set; } 
    public string Street2 { get; set; } 
    public string City { get; set; } 
    public string State { get; set; } 
    public string Zip { get; set; } 
    public string Country { get; set; } 
} 

public class Customer 
{ 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public Address Address { get; set; } 
} 

Sie diese Möglichkeiten, in ein paar tun könnte:

  1. Mit Reflexion. Führen Sie die folgenden Erweiterungsmethoden:

    public static class ObjectExtensions 
    { 
        public static IEnumerable<object> Members(this object obj) 
        { 
         if (obj == null) 
          return new object[0]; 
         var type = obj.GetType(); 
         return type.GetProperties(BindingFlags.Public | BindingFlags.Instance) 
          .Where(p => p.GetIndexParameters().Length == 0 && p.GetGetMethod(true) != null && p.CanRead) 
          .Select(p => p.GetValue(obj, new object[0])) 
          .Concat(type.GetFields().Select(f => f.GetValue(obj))); 
        } 
    
        public static bool IsDefault(this object obj) 
        { 
         if (obj == null) 
          return true; 
         var type = obj.GetType(); 
         if (type.IsValueType) 
         { 
          return obj.Equals(Activator.CreateInstance(type, true)); 
         } 
         return false; 
        } 
    
        public static bool MembersAreDefault(this object obj) 
        { 
         return obj.Members().All(v => v.IsDefault()); 
        } 
    } 
    

    Dann Customer wie folgt ändern:

    public class Customer 
    { 
        public string FirstName { get; set; } 
    
        public string LastName { get; set; } 
    
        [XmlIgnore] 
        public Address Address { get; set; } 
    
        [XmlElement("Address")] 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DebuggerBrowsable(DebuggerBrowsableState.Never)] 
        public Address SerializableAddress 
        { 
         get 
         { 
          return Address; 
         } 
         set 
         { 
          if (value != null && value.MembersAreDefault()) 
           value = null; 
          Address = value; 
         } 
        } 
    } 
    

    Die Eigenschaft SerializableAddress prüft mithilfe von Reflektion, um zu sehen, ob die eingehenden Address all Nicht-Standardwert hat.Wenn nicht, wird die zugrunde liegende Eigenschaft auf null gesetzt.

    Diese Lösung ist robust und wiederverwendbar, aber da sie Reflektion verwendet, ist die Leistung möglicherweise nicht groß.

  2. Mit einer Standardschnittstelle, um zu überprüfen, ob für einen bestimmten Typ Eigenschaften festgelegt wurden. Erstens führen die folgenden Schritte aus:

    public interface IHasDefaultMemberValues 
    { 
        bool MembersAreDefault(); 
    } 
    

    Als nächstes implementieren diese Schnittstelle für Address:

    public class Address : IHasDefaultMemberValues 
    { 
        // Properties as above. 
    
        #region IHasDefaultMemberValues Members 
    
        public virtual bool MembersAreDefault() 
        { 
         return Street1 == null && Street2 == null && City == null && State == null && Zip == null && Country == null; 
        } 
    
        #endregion 
    } 
    

    Schließlich ändern Customer identisch Lösung # 1.

    Diese Lösung ist performant, hängt jedoch davon ab, ob MembersAreDefault() korrekt verwaltet wird, wenn neue Eigenschaften zu Customer hinzugefügt werden.

+0

Danke DBC. Aber ich habe den regulären Ausdruck verwendet, um die leeren Knoten aus der Zeichenkette zu entfernen, bevor ich sie deserialisiere und das funktioniert für mich. – Mike

Verwandte Themen