序列化一个可为空的 int
Posted
技术标签:
【中文标题】序列化一个可为空的 int【英文标题】:Serialize a nullable int 【发布时间】:2010-09-19 16:27:48 【问题描述】:我有一个可以为空的 int 类?数据类型设置为序列化为 xml 元素。有没有办法设置它,如果值为 null,xml 序列化程序将不会序列化元素?
我尝试添加 [System.Xml.Serialization.XmlElement(IsNullable=false)] 属性,但我得到一个运行时序列化异常,指出存在反映类型的错误,因为“可能未设置 IsNullable为 Nullable 类型设置为 'false'。考虑使用 '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>
但是对于为 null 的 ID,我根本不需要 ID 元素,主要是因为当我在 MSSQL 中使用 OPENXML 时,对于看起来像
的元素,它返回 0 而不是 null【问题讨论】:
【参考方案1】:XmlSerializer 支持ShouldSerializeFoo()
模式,所以你可以添加一个方法:
public bool ShouldSerializeID() return ID.HasValue;
还有FooSpecified
模式 - 不确定 XmlSerializer 是否支持该模式。
【讨论】:
XmlSerializer 还支持 [FooSpecified 模式。 相关页面在这里:msdn.microsoft.com/en-us/library/53b8022e%28VS.71%29.aspx 有什么方法可以将 ShouldSerializeHasValue
。
@mark 如果对于成员(属性/字段)Foo
你也有一个public bool FooSpecified get ... set ...
,那么get
用于查看Foo
是否应该被序列化,@在反序列化期间为Foo
赋值时调用987654330@。【参考方案2】:
我正在使用这个微模式来实现 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;
这为用户提供了正确的界面而不会妥协,并且在序列化时仍然可以做正确的事情。
【讨论】:
由于 SomeValue 可能为空... public double XmlSomeValue get return SomeValue.HasValue? SomeValue.Value:0; 设置 SomeValue = 值; XmlSomeValue 只应该由 XmlSerializer 使用,只有在 XmlSomeValueSpecified 为真时才会触摸它(即 SomeValue.Value 不为空。 @pettys:这是 XML,你期待什么? ;-) 接受的答案是 2008 年的。现在应该是这个。 Interesting answer 与 Specified vs ShouldSerialize 相关 绝对应该是最佳答案。【参考方案3】:我想出了一个利用两个属性的解决方法。一个整数?具有 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());
【讨论】:
这个解决方案很棒,因为它还允许将 NULL 编码为客户端的“占位符”值,这些客户端不识别 int 中的 NULL,即 Flex。 您可以将[EditorBrowsable(EditorBrowsableState.Never)]添加到xml序列化属性中,以避免在编码时看到它【参考方案4】:哇,谢谢这个问题/答案真的帮助了我。我喜欢 ***。
我使您在上面所做的事情更加通用。我们真正想要的是让 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
【讨论】:
这会在XmlSerializer.Serialize
上向我抛出一个System.ExecutionEngineException
。【参考方案5】:
不幸的是,您描述的行为在 XmlElementAttribute.IsNullable 的文档中得到了准确的记录。
【讨论】:
【参考方案6】:非常有用的帖子帮助很大。
我选择使用 Scott 对 Nullable(Of T) 数据类型的修订,但是发布的代码仍然会在 Null 为 Null 时序列化 Nullable 元素 - 尽管没有“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 类型只需要重新键入属性。
【讨论】:
以上是关于序列化一个可为空的 int的主要内容,如果未能解决你的问题,请参考以下文章