Comment faire une valeur type nullable with.NET XmlSerializer?

supposons que j'ai cet objet:

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

le XmlSerializer sérialisera l'objet comme ceci:

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

Comment puis-je rendre l'âge de la propriété nullable? IE: ne pas sérialiser L'Âge de la propriété quand il est inférieur à 0?

j'ai essayé avec le Nullable, mais il sérialise mon objet comme cela:

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

en lisant la documentation du MSDN, j'ai trouvé ceci:

vous ne pouvez pas appliquer la propriété IsNullable à un membre tapé comme type de valeur parce qu'un type de valeur ne peut pas contenir nullNothingnullptra référence nulle (rien dans Visual Basic). De plus, vous ne pouvez pas définir cette propriété à false pour les types de valeur nulles. Lorsque ces types sont nullNothingnullptra référence nulle (rien dans Visual Basic), ils seront sérialisés en mettant xsi:nil à true.

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

je comprends qu'un type de valeur ne peut pas être défini à null. Un valuetype est toujours quelque chose. La sérialisation ne peut pas prendre la décision de sérialiser ou pas basée sur sa valeur actuelle.

j'ai essayé avec les attributs, mais ça n'a pas fonctionné. J'ai essayé de créer un objet agecontainer et de manipuler sa sérialisation avec des attributs, mais il n'a pas fonctionné.

ce que je veux vraiment c'est:

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

lorsque l'Âge de la propriété est inférieur à 0 (zéro).


semble que vous aurez à mettre en œuvre la sérialisation personnalisée.

Oui, c'est ce que je pense aussi, mais j'aimerais m'en passer.

Dans l'application, l'objet est beaucoup plus complexe, et je voudrais ne pas gérer la sérialisation moi-même.

27
demandé sur Bill the Lizard 2009-04-01 01:30:18

6 réponses

je viens de découvrir ceci. XmlSerialier cherche une propriété booléenne XXXSpecified pour déterminer si elle doit être incluse. Cela devrait résoudre le problème gentiment.

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

preuve:

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

modifier : Oui, c'est une fonctionnalité documentée. Voir la rubrique MSDN pour XmlSerializer

une Autre option est d'utiliser un modèle spécial pour créer un champ booléen reconnu par le XmlSerializer, et pour appliquer le XmlIgnoreAttribute au champ. Le modèle est créé sous la forme de propertynamespécified. Par exemple, s'il y a un champ nommé "MyFirstName", vous créerez aussi un champ nommé "Myfirstnamespécified" qui indique au XmlSerializer s'il doit générer l'élément XML nommé "MyFirstName".

51
répondu Samuel 2009-03-31 23:01:36

extension de la réponse de Samuel et du commentaire de Greg Beech au cas d'une propriété booléenne: si la propriété est de type bool alors vous ne pouvez pas écrire un test simple dans la propriété propertys specified.

une solution est d'utiliser un type Nullable, alors le test dans la propriété propertyspécified est une simple propriété.HasValue. par exemple

using System.Xml.Serialization;

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

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

une alternative à l'utilisation d'un type nul pour une propriété numérique (suggéré par Greg Beech) est de définir la propriété value à une valeur par défaut non valide, telle que -1, comme suit:

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
répondu jumpalongjim 2009-12-11 12:13:18

vous pouvez utiliser Xmdelementattribute.IsNullable :

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

    public int MyClassB { get; set; }
}
4
répondu Yochai Timmer 2013-12-18 07:51:25

cela devrait aider Faire de l'Âge de l'int? et..

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

..cela signifie ajouter les méthodes ShouldSerializeXXX à votre classe!

2
répondu Dog Ears 2009-03-31 22:03:27

d'Oublier les valeurs null ... ShouldSerializeXXX est une jolie solution. Ici L'Âge sera sérialisé sur votre condition.

[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
répondu hoang 2009-11-12 15:02:17

xsd.exe va autogénérer la propriété et les accesseurs XXXS spécifiés si vous définissez l'attribut 'minoccurs' comme 'minoccurs="0"' pour un élément ... si vous utilisez un schéma pour définir votre xml/classe

0
répondu JustAsItSounds 2010-03-16 03:23:58