序列化可为null的int


92

我有一个带有可为null的int的类?设置为序列化为xml元素的数据类型。有什么方法可以设置它,以便xml序列化程序在值为null时不会序列化元素?

我尝试添加[System.Xml.Serialization.XmlElement(IsNullable = false)]属性,但是我收到一个运行时序列化异常,提示存在反映该类型的错误,因为“ IsNullable可能未设置为'false “表示Nullable类型。请考虑使用“ System.Int32”类型或从XmlElement属性中删除IsNullable属性。”

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

但是对于ID为空的ID,我根本不需要ID元素,主要是因为当我在MSSQL中使用OPENXML时,它为看起来像这样的元素返回0而不是null

Answers:


149

XmlSerializer支持该ShouldSerialize{Foo}()模式,因此您可以添加一个方法:

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

还有一种{Foo}Specified模式-不确定XmlSerializer是否支持该模式。


8
XmlSerializer也支持[Foo} Specified模式。
David Schmitt,2009年


1
有什么方法可以将ShouldSerialize <prop>与自动生成的属性一起使用?即没有局部变量。
杰伊,2010年

1
@杰伊:不需要一个。您可以仅致电HasValue酒店。
史蒂文·苏迪特

1
@mark如果对于成员(属性/字段)Foo也有一个public bool FooSpecified {get {...} set {...}},则get使用来查看是否Foo应进行序列化,并在反序列化期间为set分配值时调用Foo
马克·格雷夫

26

我正在使用此微型模式来实现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; } }

这为用户提供了正确的界面而没有任何妥协,并且在序列化时仍然可以执行正确的操作。


1
由于SomeValue可能为null ... public double XmlSomeValue {get {return SomeValue.HasValue?SomeValue.Value:0; }设置{SomeValue = value; }
道格·多梅尼

XmlSomeValue只应该由XmlSerializer的谁就会只接触它时,XmlSomeValueSpecified是真(即SomeValue.Value不是null时使用。
大卫·施密特

@pettys:是XML,您期望什么?;-)
David Schmitt

公认的答案是从2008年开始。这个应该是现在的答案。与“ Specified vs ShouldSerialize”相关的有趣答案
daniloquio

绝对应该是最佳答案。
tyteen4a03 '17

12

我想出了一种利用两个属性的解决方法。一个整数?具有XmlIgnore属性的属性和要序列化的object属性。

    /// <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());
            }
        }
    }

该解决方案很棒,因为它还允许将NULL编码为客户端的“占位符”值,这些客户端无法识别int形式的NULL,即Flex。
2013年

您可以将[EditorBrowsable(EditorBrowsableState.Never)]添加到xml序列化属性中,以防止在编码时看到它
AntonioRodríguez

6

哇,谢谢,这个问题/答案确实帮助了我。我心里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>代替),但除此之外,所有行为都保持不变。


1
这将引发System.ExecutionEngineExceptionXmlSerializer.Serialize我。
马丁·布劳恩


1

非常有用的发布帮助了很多人。

我选择对Scott的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类型只需要重新键入属性即可。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.