web-dev-qa-db-de.com

Wie mache ich einen Werttyp mit .NET XmlSerializer nullbar?

Nehmen wir an, ich habe folgendes Objekt:

[Serializable]
public class MyClass
{
    public int Age { get; set; }
    public int MyClassB { get; set; }
}
[Serializable]
public class MyClassB
{
    public int RandomNumber { get; set; }
}

Der XmlSerializer serialisiert das Objekt folgendermaßen:

<MyClass>
    <Age>0</age>
    <MyClassB>
        <RandomNumber>4234</RandomNumber>
    </MyClassB>
</MyClass>

Wie kann ich die Eigenschaft Age nullable machen? IE: um die Eigenschaft Alter nicht zu serialisieren, wenn es unter 0 ist?

Ich habe es mit der Nullable versucht, aber sie serialisiert mein Objekt folgendermaßen:

<MyClass>
    <Age d5p1:nil="true" />
    <MyClassB>
        <RandomNumber>4234</RandomNumber>
    </MyClassB>
</MyClass>    

Beim Lesen der MSDN-Dokumentation habe ich Folgendes festgestellt:

Sie können die IsNullable-Eigenschaft nicht auf einen als Werttyp eingegebenen Member anwenden, da ein Werttyp keine nullNothingnullptra-Nullreferenz (Nothing in Visual Basic) enthalten darf. Darüber hinaus können Sie diese Eigenschaft für nullfähige Werttypen nicht auf false festlegen. Wenn solche Typen nullNothingnullptra-Nullreferenzen (Nothing in Visual Basic) sind, werden sie serialisiert, indem xsi: nil auf true gesetzt wird.

quelle: http://msdn.Microsoft.com/en-us/library/system.xml.serialization.xmlelementattribute.isnullable.aspx

Ich verstehe, dass ein Werttyp nicht auf null gesetzt werden kann. Ein Wertetyp ist immer auf etwas gesetzt. Die Serialisierung kann nicht die Entscheidung treffen, sie zu serialisieren, oder sie basiert nicht auf ihrem aktuellen Wert.

Ich habe es mit den Attributen versucht, aber es hat nicht geklappt. Ich habe versucht, ein agecontainer-Objekt zu erstellen und seine Serialisierung mit Attributen zu bearbeiten, aber es hat nicht funktioniert.

Was ich wirklich will, ist:

<MyClass>
    <MyClassB>
        <RandomNumber>4234</RandomNumber>
    </MyClassB>
</MyClass>

Wenn die Eigenschaft Alter unter 0 (Null) liegt.


Sieht so aus, als müssten Sie eine benutzerdefinierte Serialisierung implementieren.

Ja, das ist es, was ich auch, aber ich möchte ohne es davonkommen.

In der Anwendung ist das Objekt viel komplexer, und ich möchte die Serialisierung nicht selbst behandeln.

28
Jean-Francois

Ich habe das gerade entdeckt. XmlSerialier sucht nach einer booleschen XXXSpecified-Eigenschaft, um festzustellen, ob sie enthalten sein soll. Dies sollte das Problem gut lösen.

[Serializable]
public class MyClass
{
  public int Age { get; set; }
  [XmlIgnore]
  public bool AgeSpecified { get { return Age >= 0; } }
  public int MyClassB { get; set; }
}

[Serializable]
public class MyClassB
{
  public int RandomNumber { get; set; }
}

Beweis:

static string Serialize<T>(T obj)
{
  var serializer = new XmlSerializer(typeof(T));
  var builder = new StringBuilder();
  using (var writer = new StringWriter(builder))
  {
    serializer.Serialize(writer, obj);
    return builder.ToString();
  }
}

static void Main(string[] args)
{
  var withoutAge = new MyClass() { Age = -1 };
  var withAge = new MyClass() { Age = 20 };

  Serialize(withoutAge); // = <MyClass><MyClassB>0</MyClassB></MyClass>
  Serialize(withAge); // = <MyClass><Age>20</Age><MyClassB>0</MyClassB></MyClass>
}

Edit : Ja, es handelt sich um eine dokumentierte Funktion. Siehe den MSDN-Eintrag für XmlSerializer

Eine andere Option besteht darin, ein spezielles Muster zu verwenden, um ein vom XmlSerializer erkanntes boolesches Feld zu erstellen und das XmlIgnoreAttribute auf das Feld anzuwenden. Das Muster wird in Form von propertyNameSpecified erstellt. Wenn es beispielsweise ein Feld mit dem Namen "MyFirstName" gibt, erstellen Sie auch ein Feld mit dem Namen "MyFirstNameSpecified", das den XmlSerializer anweist, ob das XML-Element "MyFirstName" generiert werden soll.

53
Samuel

Erweiterung von Samuels Antwort und Greg Beechs Kommentar auf den Fall einer booleschen Eigenschaft: Wenn die Eigenschaft vom Typ bool ist, können Sie keinen einfachen Test in die Eigenschaft propertySpecified schreiben.

Eine Lösung ist die Verwendung eines Nullable <bool> -Typs. Dann ist der Test in der propertySpecified-Eigenschaft einfach property.HasValue. z.B.

using System.Xml.Serialization;

public class Person
{
    public bool? Employed { get; set; }

    [XmlIgnore]
    public bool EmployedSpecified { get { return Employed.HasValue; } }
}

Eine Alternative zur Verwendung eines nullfähigen Typs für eine numerische Eigenschaft (vorgeschlagen von Greg Beech) besteht darin, die value -Eigenschaft wie folgt auf einen ungültigen Standardwert wie -1 zu setzen:

using System.ComponentModel;
using System.Xml.Serialization;

public class Person
{
    [DefaultValue(-1)]
    public int Age { get; set; }

    [XmlIgnore]
    public bool AgeSpecified { get { return Age >= 0; } }
}
13
jumpalongjim

Sie könnenXmlElementAttribute.IsNullableverwenden:

[Serializable]
public class MyClass
{
    [XmlElement(IsNullable = true)]
    public int? Age { get; set; }

    public int MyClassB { get; set; }
}
4
Yochai Timmer

Dies sollte helfen Make Age int? und..

public bool ShouldSerializeAge() { return Age.HasValue; }

..es bedeutet, dass Sie Ihrer Klasse die ShouldSerializeXXX-Methoden hinzufügen müssen!

2
Dog Ears

Vergessen Sie Nullable ... ShouldSerializeXXX ist eine hübsche Lösung. Hier wird Age nach Ihrer Bedingung serialisiert.

[Serializable]
public class MyClass
{
    public int Age { get; set; }
    public int MyClassB { get; set; }

    #region Conditional Serialization
    public bool ShouldSerializeAge() { return age > 0; }
    #endregion
}

[Serializable]
public class MyClassB
{
    public int RandomNumber { get; set; }
}
0
hoang

xsd.exe generiert automatisch die Eigenschaft XXXSpecified und die Zugriffsmethoden, wenn Sie das 'minoccurs'-Attribut als' minoccurs = "0" "für ein Element festlegen ... wenn Sie ein Schema zum Definieren Ihrer xml/class verwenden

0
JustAsItSounds