it-swarm.dev

Jak provést hodnotu typu nullable s .NET XmlSerializer?

Předpokládejme, že mám tento objekt:

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

XmlSerializer bude serializovat objekt takto:

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

Jak mohu učinit majetek Age nullable? IE: není serializovat vlastnost Age, když je pod 0?

Snažil jsem se s Nullable, ale serializovat můj objekt takhle:

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

Přečtením dokumentace MSDN jsem zjistil:

Nelze použít vlastnost IsNullable člen zadaný jako typ hodnoty, protože typ hodnoty nemůže obsahovat nullNothingnullptra null odkaz (nic v jazyce Visual Basic). Tuto vlastnost navíc nelze nastavit na hodnotu false pro typy hodnot s hodnotou Null. Pokud tyto typy jsou nullNothingnullptra null odkaz (nic v jazyce Visual Basic), budou serializovány nastavením xsi: nil na hodnotu true.

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

Rozumím, že typ hodnoty nelze nastavit na hodnotu null. Cenový typ je vždy nastaven na něco. Serializace nemůže učinit rozhodnutí serializovat nebo ne na základě jeho aktuální hodnoty.

Snažil jsem se s atributy, ale to nevyšlo. Snažil jsem se vytvořit objekt agecontainer a manipulovat s jeho serializací s atributy, ale nevyšlo to.

Co opravdu chci je:

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

Když je vlastnost Věk nižší než 0 (nula).


Vypadá to, že budete muset implementovat vlastní serializaci.

Jo, to je to, co já taky, ale rád bych se bez toho.

V aplikaci je objekt mnohem složitější a já bych se ráda serializaci nezvládla sama.

28
Jean-Francois

Právě jsem to objevil. XmlSerialier hledá vlastnost XXXSpecified boolean k určení, zda má být zahrnuta. To by mělo tento problém pěkně vyřešit.

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

Důkaz:

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 : Ano, jedná se o dokumentovanou funkci. Viz položka MSDN pro XmlSerializer

Další možností je použít speciální vzor k vytvoření booleovského pole rozpoznaného nástrojem XmlSerializer a použít XmlIgnoreAttribute na pole. Vzorek je vytvořen ve formě vlastnostiNameName. Například pokud je pole s názvem "MyFirstName" také vytvořit pole s názvem "MyFirstNameSpecified", který pokyn XmlSerializer, zda generovat prvek XML s názvem "MyFirstName".

53
Samuel

Rozšíření Samuelovy odpovědi a komentáře Grega Beecha o případ booleovské vlastnosti: pokud je vlastnost typu bool, pak nemůžete zapsat jednoduchý test do vlastnosti propertySpecified.

Řešením je použití typu Nulovatelný <bool>, pak test v vlastnosti propertySpecified je prostě vlastnost.HasValue. např.

using System.Xml.Serialization;

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

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

Alternativou k použití nulovatelného typu pro číselnou vlastnost (navrhl Greg Beech) je nastavit vlastnost value na neplatnou výchozí hodnotu, například -1, následujícím způsobem:

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

Můžete použítXmlElementAttribute.IsNullable:

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

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

To by mělo pomoci vytvořit věk int? a..

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

..znamená to přidání metod ShouldSerializeXXX do vaší třídy!

2
Dog Ears

Zapomeňte na Nullable ... ShouldSerializeXXX je pěkné řešení. Zde bude věk serializován na vašem stavu.

[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 bude automaticky generovat vlastnost a přístupové body XXXSpecified, pokud nastavíte atribut 'minoccurs' jako 'minoccurs = "0" pro element ... pokud používáte schéma pro definování vaší xml/class

0
JustAsItSounds