У меня есть класс с обнуляемым int? тип данных установлен для сериализации как элемент xml. Есть ли способ настроить его так, чтобы сериализатор xml не сериализовал элемент, если значение равно нулю?
Я пытался добавить атрибут [System.Xml.Serialization.XmlElement (IsNullable = false)], но получаю исключение сериализации во время выполнения, в котором говорится, что произошла ошибка, отражающая тип, потому что для параметра IsNullable не может быть установлено значение 'false "для типа, допускающего значение NULL. Рассмотрите возможность использования типа" 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 вместо нуля для элемента, который выглядит как
источник
HasValue
в собственность.Foo
вас также есть apublic bool FooSpecified {get {...} set {...}}
, тоget
используется, чтобы увидеть,Foo
следует ли сериализовать, иset
вызывается при присвоении значения воFoo
время десериализации.Я использую этот микро-шаблон для реализации сериализации, допускающей значение NULL:
[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()); } } }
источник
Вау, спасибо, этот вопрос / ответ мне действительно помог. Я люблю Stackoverflow.
Я сделал то, что вы делаете выше, более общим. Все, что нам действительно нужно, это иметь 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 <int>), но в остальном все поведение остается прежним.
источник
System.ExecutionEngineException
ONXmlSerializer.Serialize
на меня.К сожалению, описываемое вами поведение точно задокументировано как таковое в документации для XmlElementAttribute.IsNullable.
источник
Очень полезная публикация очень помогла.
Я решил пойти с ревизией Скотта для типа данных 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
Я предпочитаю этот метод использованию шаблона Specified (foo), так как для этого требуется добавить множество избыточных свойств к моим объектам, тогда как использование нового типа Nullable требует лишь повторного ввода свойств.
источник