2009-03-31 15 views
25

Supongamos que tengo este objeto:¿Cómo hacer un tipo de valor anulable con .NET XmlSerializer?

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

XmlSerializer serializa el objeto de esa manera:

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

Como puedo tomado la Edad anulable propiedad? IE: ¿para no serializar la propiedad Age cuando está por debajo de 0?

he intentado con la anulable, pero serializar mi objeto de esa manera:

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

Mediante la lectura de la documentación de MSDN encontré esto:

No se puede aplicar la propiedad IsNullable a un miembro de mecanografiado como un tipo de valor porque un tipo de valor no puede contener nullNothingnullptra referencia nula (Nothing en Visual Basic). Además, no puede establecer esta propiedad en falso para los tipos de valores que se pueden anotar. Cuando dichos tipos son null No hay referencia nula nula (Nothing en Visual Basic), se serializarán estableciendo xsi: nil en true.

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

entiendo un tipo de valor no se puede establecer en nulo. Un tipo de valor siempre se establece en algo. La serialización no puede tomar la decisión de serializarlo o no en función de su valor actual.

Intenté con los atributos, pero no funcionó. Intenté crear un objeto agecontainer y manipular su serialización con atributos, pero no funcionó.

Lo que realmente quiero es:

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

Cuando la Edad propiedad está por debajo de 0 (cero).


Parece que tendrá que aplicar la serialización personalizado.

Sí, eso es lo que también pensé, pero me gustaría escapar sin él.

En la aplicación, el objeto es mucho más complejo, y me gustaría no manejar la serialización.

Respuesta

49

Acabo de descubrir esto. XmlSerialier busca una propiedad booleana XXXSpecified para determinar si debe incluirse. Esto debería resolver el problema muy bien.

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

Prueba:

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

Editar: Sí, es una característica documentada.Ver la MSDN entry for XmlSerializer

Otra opción es utilizar un patrón especial para crear un campo booleano reconocido por el XmlSerializer, y para aplicar el XmlIgnoreAttribute al campo. El patrón se crea en forma de propertyNameSpecified. Por ejemplo, si hay un campo llamado "MyFirstName" también creará un campo llamado "MyFirstNameSpecified" que indica al XmlSerializer si debe generar el elemento XML llamado "MyFirstName".

+1

+1 eso es un buen truco! ¿Sabes si es una característica no documentada o si es totalmente compatible? – James

+0

@James que ha estado allí antes de anulables, por lo que debería funcionar bien :) Lo usé hace un tiempo y no tuve ningún problema. – eglasius

+0

¿Pero es una función documentada (y por lo tanto, compatible)? –

2

Esto debería ayudar Make Age int? y ..

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

..it significa agregar los métodos ShouldSerializeXXX a su clase!

+0

Además, de acuerdo con el documento MSDN, deberíamos implementar el método resetXXX, que simplemente lo configuraría como nulo nuevamente. Los dos métodos parecen funcionar juntos. –

0

Olvídate de Nullable ... ShouldSerializeXXX es una solución bonita. Aquí, Age se serializará según su condición.

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

La extensión de la respuesta de Samuel y el comentario de Greg Haya para el caso de una propiedad booleana: si la propiedad es de tipo bool entonces no se puede escribir una prueba sencilla en la propiedad propertySpecified.

Una solución es utilizar un tipo < bool Nullable > tipo, entonces la prueba en la propiedad propertySpecified es simplemente property.HasValue. p.ej.

using System.Xml.Serialization; 

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

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

Una alternativa al uso de un tipo anulable para una propiedad numérica (sugerido por Greg haya) es para establecer la propiedad valor a un valor predeterminado no válida, tal como -1, como sigue:

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

xsd.exe generará automáticamente la propiedad y accesos de XXXSpecified si establece el atributo 'minoccurs' como 'minoccurs = "0"' para un elemento ... si está utilizando un esquema para definir su xml/clase

+0

-1: gracias por intentar responder la pregunta, pero está claro por la pregunta que el PO comenzó con los objetos, no con el esquema. –

+0

Realmente fue muy útil para mí, gracias – Guillaume86

4

Usted puede usar XmlElementAttribute.IsNullable :

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

    public int MyClassB { get; set; } 
} 
Cuestiones relacionadas