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:
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ß.
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.
Können Sie die C# für Ihre "Kunden" - und "Adress" -Klassen teilen? – dbc
Bitte a [mcve] einbeziehen. –