Сериализовать nullable int


у меня есть класс с nullable int? тип данных, заданный для сериализации в виде xml-элемента. Есть ли способ настроить его так, чтобы XML-сериализатор не сериализовал элемент, если значение равно null?

Я попытался добавить [System.XML.Сериализация.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>

но для идентификаторов, которые являются null я не хочу элемент ID вообще, в первую очередь потому, что когда я использую OPENXML в MSSQL, он возвращает 0 вместо null для элемента, который выглядит как

6 85

6 ответов:

XmlSerializer поддерживает ShouldSerialize{Foo}() шаблон, так что вы можете добавить метод:

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

есть еще {Foo}Specified pattern-не уверен, что XmlSerializer поддерживает это.

Я использую этот микро-шаблон для выполнения сериализации значение 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());
            }
        }
    }

Вау Спасибо этот вопрос / ответ действительно помог мне. I heart 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), но кроме этого все поведение остается прежним.

к сожалению, поведение, которое вы описываете, точно документировано как таковое в docs for 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

Я предпочитаю этот метод с помощью (foo)указанный шаблон, как это требует добавления ведро нагрузок избыточных свойств для моих объектов, в то время как использование нового типа Nullable просто требует перепечатки свойств.