Serializar um int anulável

Eu tenho uma class com um int anulável? Tipo de dados definido para serializar como um elemento xml. Existe alguma maneira de configurá-lo para que o serializador xml não serializará o elemento se o valor for nulo?

Eu tentei adicionar o atributo [System.Xml.Serialization.XmlElement (IsNullable = false)], mas eu recebo uma exceção de serialização de tempo de execução dizendo que houve um erro refletindo o tipo, porque “IsNullable não pode ser definido como ‘false ‘para um tipo anulável. Considere usar o tipo’ System.Int32 ‘ou remover a propriedade IsNullable do atributo XmlElement. ”

[Serializable] [System.Xml.Serialization.XmlRoot("Score", Namespace = "http://mycomp.com/test/score/v1")] public class Score { private int? iID_m; ... ///  /// ///  public int? ID { get { return iID_m; } set { iID_m = value; } } ... } 

A class acima será serializada para:

    

Mas para IDs que são nulos eu não quero o elemento ID, principalmente porque quando eu uso OPENXML no MSSQL, ele retorna um 0 em vez de null para um elemento que se parece com

XmlSerializer suporta o padrão ShouldSerialize{Foo}() , portanto, você pode adicionar um método:

 public bool ShouldSerializeID() {return ID.HasValue;} 

Há também o padrão {Foo}Specified – não tenho certeza se o XmlSerializer suporta esse padrão.

Eu estou usando este micro-padrão para implementar serialização 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; } } 

Isso fornece a interface certa para o usuário sem comprometer e ainda faz a coisa certa ao serializar.

Eu descobri uma solução utilizando duas propriedades. Um int? propriedade com um atributo XmlIgnore e uma propriedade de object que é serializada.

  ///  /// Score db record ///  [System.Xml.Serialization.XmlIgnore()] public int? ID { get { return iID_m; } set { iID_m = value; } } ///  /// Score db record ///  [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()); } } } 

Uau, graças a esta pergunta / resposta realmente me ajudou. Eu coração Stackoverflow.

Eu fiz o que você está fazendo acima de um pouco mais genérico. Tudo o que estamos realmente procurando é ter o Nullable com comportamento de serialização ligeiramente diferente. Eu usei o Reflector para criar meu próprio Nullable e adicionei algumas coisas aqui e ali para fazer a serialização de XML funcionar da maneira que queremos. Parece funcionar muito bem:

 public class Nullable { 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 i_value) { return i_value.Value; } public static implicit operator Nullable(T i_value) { return new Nullable(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; } 

Você perde a capacidade de ter seus membros como int? e assim por diante (tem que usar Nullable ), mas diferente de tudo, o comportamento permanece o mesmo.

Infelizmente, os comportamentos que você descreve são documentados com precisão nos documentos para XmlElementAttribute.IsNullable.

Postagens muito úteis ajudaram muito.

Eu optei por ir com revisão de Scott para o tipo de dados Nullable (Of T), no entanto, o código postado ainda serializa o elemento Nullable quando é nulo – embora sem o atributo “xs: nil = ‘true'”.

Eu precisava forçar o serializador a soltar a tag completamente, então simplesmente implementei o IXmlSerializable na estrutura (isso é no VB, mas você obtém a imagem):

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

Eu prefiro esse método para usar o padrão (foo) especificado que requer a adição de cargas de bucket de propriedades redundantes aos meus objects, enquanto que usar o novo tipo Nullable requer apenas a redigitação das propriedades.