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