c# - net - Serializar una int intérprete de notas
system xml serialization xmlserializer vb net (6)
Tengo una clase con un int nullable? datatype configurado para serializar como un elemento xml. ¿Hay alguna forma de configurarlo para que el serializador xml no serialice el elemento si el valor es nulo?
Intenté agregar el atributo [System.Xml.Serialization.XmlElement (IsNullable = false)], pero recibí una excepción de serialización en tiempo de ejecución que decía que había un error que reflejaba el tipo, porque "IsNullable no puede configurarse como ''falso ''para un tipo Nullable. Considere usar el tipo'' System.Int32 ''o eliminar la propiedad IsNullable del atributo XmlElement. "
[Serializable]
[System.Xml.Serialization.XmlRoot("Score", Namespace = "http://mycomp.com/test/score/v1")]
public class Score
{
private int? iID_m;
...
/// <summary>
///
/// </summary>
public int? ID
{
get
{
return iID_m;
}
set
{
iID_m = value;
}
}
...
}
La clase anterior se serializará a:
<Score xmlns="http://mycomp.com/test/score/v1">
<ID xsi:nil="true" />
</Score>
Pero para los identificadores que son nulos, no quiero el elemento ID en absoluto, principalmente porque cuando uso OPENXML en MSSQL, devuelve un 0 en lugar de nulo para un elemento que se parece a
Desafortunadamente, los comportamientos que describes están documentados con precisión como tales en los documentos para XmlElementAttribute.IsNullable.
Descubrí una solución utilizando dos propiedades. Un int? propiedad con un atributo XmlIgnore y una propiedad de objeto que se serializa.
/// <summary>
/// Score db record
/// </summary>
[System.Xml.Serialization.XmlIgnore()]
public int? ID
{
get
{
return iID_m;
}
set
{
iID_m = value;
}
}
/// <summary>
/// Score db record
/// </summary>
[System.Xml.Serialization.XmlElement("ID",IsNullable = false)]
public object IDValue
{
get
{
return ID;
}
set
{
if (value == null)
{
ID = null;
}
else if (value is int || value is int?)
{
ID = (int)value;
}
else
{
ID = int.Parse(value.ToString());
}
}
}
Estoy usando este micro-patrón para implementar la serialización Nullable:
[XmlIgnore]
public double? SomeValue { get; set; }
[XmlAttribute("SomeValue")] // or [XmlElement("SomeValue")]
[EditorBrowsable(EditorBrowsableState.Never)]
public double XmlSomeValue { get { return SomeValue.Value; } set { SomeValue= value; } }
[EditorBrowsable(EditorBrowsableState.Never)]
public bool XmlSomeValueSpecified { get { return SomeValue.HasValue; } }
Esto proporciona la interfaz correcta para el usuario sin compromiso y sigue haciendo lo correcto al serializar.
La publicación muy útil ayudó mucho.
Opté por ir con la revisión de Scott al tipo de datos Nullable (Of T), sin embargo, el código publicado todavía serializa el elemento Nullable cuando es nulo, aunque sin el atributo "xs: nil = ''true''".
Necesitaba obligar al serializador a soltar la etiqueta por completo, así que simplemente implementé IXmlSerializable en la estructura (esto está en VB pero obtienes la imagen):
''----------------------------------------------------------------------------
'' GetSchema
''----------------------------------------------------------------------------
Public Function GetSchema() As System.Xml.Schema.XmlSchema Implements System.Xml.Serialization.IXmlSerializable.GetSchema
Return Nothing
End Function
''----------------------------------------------------------------------------
'' ReadXml
''----------------------------------------------------------------------------
Public Sub ReadXml(ByVal reader As System.Xml.XmlReader) Implements System.Xml.Serialization.IXmlSerializable.ReadXml
If (Not reader.IsEmptyElement) Then
If (reader.Read AndAlso reader.NodeType = System.Xml.XmlNodeType.Text) Then
Me._value = reader.ReadContentAs(GetType(T), Nothing)
End If
End If
End Sub
''----------------------------------------------------------------------------
'' WriteXml
''----------------------------------------------------------------------------
Public Sub WriteXml(ByVal writer As System.Xml.XmlWriter) Implements System.Xml.Serialization.IXmlSerializable.WriteXml
If (_hasValue) Then
writer.WriteValue(Me.Value)
End If
End Sub
Prefiero este método al uso del patrón Especificado (foo), ya que eso requiere agregar cargas compartidas de propiedades redundantes a mis objetos, mientras que usar el nuevo tipo Nullable solo requiere volver a escribir las propiedades.
Wow gracias esta pregunta / respuesta realmente me ayudó. I corazón .
Hice lo que estás haciendo por encima de un poco más genérico. Todo lo que realmente estamos buscando es tener Nullable con un comportamiento de serialización ligeramente diferente. Usé Reflector para construir mi propio Nullable, y agregué algunas cosas aquí y allá para hacer que la serialización XML funcione de la manera que queremos. Parece funcionar bastante bien:
public class Nullable<T>
{
public Nullable(T value)
{
_value = value;
_hasValue = true;
}
public Nullable()
{
_hasValue = false;
}
[XmlText]
public T Value
{
get
{
if (!HasValue)
throw new InvalidOperationException();
return _value;
}
set
{
_value = value;
_hasValue = true;
}
}
[XmlIgnore]
public bool HasValue
{ get { return _hasValue; } }
public T GetValueOrDefault()
{ return _value; }
public T GetValueOrDefault(T i_defaultValue)
{ return HasValue ? _value : i_defaultValue; }
public static explicit operator T(Nullable<T> i_value)
{ return i_value.Value; }
public static implicit operator Nullable<T>(T i_value)
{ return new Nullable<T>(i_value); }
public override bool Equals(object i_other)
{
if (!HasValue)
return (i_other == null);
if (i_other == null)
return false;
return _value.Equals(i_other);
}
public override int GetHashCode()
{
if (!HasValue)
return 0;
return _value.GetHashCode();
}
public override string ToString()
{
if (!HasValue)
return "";
return _value.ToString();
}
bool _hasValue;
T _value;
}
¿Pierdes la habilidad de tener tus miembros como int? y así sucesivamente (tienen que usar Nullable <int> en su lugar), pero aparte de eso, todo el comportamiento permanece igual.
XmlSerializer admite el patrón ShouldSerialize{Foo}()
, por lo que puede agregar un método:
public bool ShouldSerializeID() {return ID.HasValue;}
También está el patrón {Foo}Specified
; no estoy seguro de si XmlSerializer es compatible con ese.