Сериализировать обнуляемый int
У меня есть класс с обнуляемым int? тип данных установлен для сериализации как элемент xml. Есть ли способ настроить его так, чтобы сериализатор xml не сериализовал элемент, если значение равно нулю?
Я попытался добавить атрибут [System.Xml.Serialization.XmlElement(IsNullable=false)], но я получаю исключение сериализации во время выполнения, сообщающее, что произошла ошибка, отражающая тип, потому что для IsNullable не может быть установлено значение "false" "для типа Nullable. Попробуйте использовать тип" System.Int32 "или удалите свойство IsNullable из атрибута 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;
}
}
...
}
Вышеуказанный класс будет сериализован в:
<Score xmlns="http://mycomp.com/test/score/v1">
<ID xsi:nil="true" />
</Score>
Но для идентификаторов, которые являются нулевыми, я вообще не хочу элемент идентификатора, прежде всего потому, что когда я использую OPENXML в MSSQL, он возвращает 0 вместо нуля для элемента, который выглядит как
7 ответов
XmlSerializer поддерживает ShouldSerialize{Foo}()
шаблон, так что вы можете добавить метод:
public bool ShouldSerializeID() {return ID.HasValue;}
Также есть {Foo}Specified
шаблон - не уверен, что XmlSerializer поддерживает это.
Я использую этот микро-шаблон для реализации сериализации 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; } }
Это обеспечивает правильный интерфейс для пользователя без компромиссов и, тем не менее, делает правильные вещи при сериализации.
Я нашел обходной путь, используя два свойства. Int? свойство с атрибутом XmlIgnore и свойством объекта, которое сериализуется.
/// <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());
}
}
}
Вау, спасибо, этот вопрос / ответ действительно помог мне. Я сердце Stackru.
Я сделал то, что вы делаете выше, немного более общим. Все, что мы действительно ищем, это иметь Nullable с немного другим поведением сериализации. Я использовал Reflector для создания собственного Nullable и добавил кое-что, чтобы сериализация XML работала так, как мы хотим. Кажется, работает довольно хорошо:
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;
}
Вы теряете способность иметь своих членов как int? и так далее (вместо этого нужно использовать Nullable
Очень полезная публикация очень помогла.
Я решил перейти с пересмотром Скотта на тип данных Nullable(Of T), однако опубликованный код все еще сериализует элемент Nullable, когда он имеет значение Null - хотя и без атрибута "xs:nil='true" ".
Мне нужно было заставить сериализатор полностью отбросить тег, поэтому я просто реализовал IXmlSerializable на структуре (это в VB, но вы получите картину):
'----------------------------------------------------------------------------
' 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
Я предпочитаю этот метод использованию шаблона (foo)Specified, так как для этого требуется добавить в мои объекты избыточную загрузку избыточных свойств, тогда как использование нового типа Nullable просто требует повторного ввода свойств.
К сожалению, поведение, которое вы описываете, точно задокументировано как таковое в документах для XmlElementAttribute.IsNullable.
[XmlIgnore]
public int? Revision { get; set; }
[XmlAttribute("Revision")]
public string RevisionAsString
{
get => Revision?.ToString();
set => Revision = string.IsNullOrEmpty(value) ? default : int.Parse(value);
}
public bool ShouldSerializeRevisionAsString()
{
return Revision.HasValue;
}