C# 序列化一个可为空的 int
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/244953/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Serialize a nullable int
提问by Jeremy
I have a class with a nullable int? datatype set to serialize as an xml element. Is there any way to set it up so the xml serializer will not serialize the element if the value is null?
我有一个可以为空的 int 类?数据类型设置为序列化为 xml 元素。有没有办法设置它,以便 xml 序列化器在值为 null 时不会序列化元素?
I've tried to add the [System.Xml.Serialization.XmlElement(IsNullable=false)] attribute, but I get a runtime serialization exception saying there was a an error reflecting the type, because "IsNullable may not be set to 'false' for a Nullable type. Consider using 'System.Int32' type or removing the IsNullable property from the XmlElement attribute."
我尝试添加 [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;
}
}
...
}
The above class will serialize to:
上面的类将序列化为:
<Score xmlns="http://mycomp.com/test/score/v1">
<ID xsi:nil="true" />
</Score>
But for IDs that are null I don't want the ID element at all, primarily because when I use OPENXML in MSSQL, it returns a 0 instead of null for an element that looks like
但是对于为空的 ID,我根本不想要 ID 元素,主要是因为当我在 MSSQL 中使用 OPENXML 时,对于看起来像这样的元素,它返回 0 而不是 null
采纳答案by Marc Gravell
XmlSerializer supports the ShouldSerialize{Foo}()
pattern, so you can add a method:
XmlSerializer 支持该ShouldSerialize{Foo}()
模式,因此您可以添加一个方法:
public bool ShouldSerializeID() {return ID.HasValue;}
There is also the {Foo}Specified
pattern - not sure if XmlSerializer supports that one.
还有一种{Foo}Specified
模式 - 不确定 XmlSerializer 是否支持该模式。
回答by Serge Wautier
Unfortunately, the behaviours you describe are accurately documented as such in the docs for XmlElementAttribute.IsNullable.
不幸的是,您描述的行为在 XmlElementAttribute.IsNullable 的文档中得到了准确的记录。
回答by Jeremy
I figured out a workaround utilizing two properties. An int? property with an XmlIgnore attribute and an object property which gets serialized.
我想出了一个利用两个属性的解决方法。一个整数?具有 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());
}
}
}
回答by scobi
Wow thanks this question/answer really helped me out. I heart Stackoverflow.
哇谢谢这个问题/答案真的帮助了我。我很喜欢 Stackoverflow。
I made what you are doing above a little more generic. All we're really looking for is to have Nullable with slightly different serialization behavior. I used Reflector to build my own Nullable, and added a few things here and there to make the XML serialization work the way we want. Seems to work pretty well:
我让你在上面做的事情更通用一些。我们真正要寻找的是 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;
}
You lose the ability to have your members as int? and so on (have to use Nullable<int> instead) but other than that all behavior stays the same.
你失去了让你的成员成为 int 的能力?等等(必须使用 Nullable<int> 代替),但除此之外,所有行为都保持不变。
回答by David Schmitt
I'm using this micro-pattern to implement Nullable serialization:
我正在使用这个微模式来实现 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; } }
This provides the right interface to the user without compromise and still does the right thing when serializing.
这为用户提供了正确的界面而不会妥协,并且在序列化时仍然做正确的事情。
回答by James Close
Very useful posting helped a great deal.
非常有用的帖子帮助很大。
I opted to go with Scott's revision to the Nullable(Of T) datatype, however the code posted still serializes the Nullable element when it is Null - albeit without the "xs:nil='true'" attribute.
我选择使用 Scott 对 Nullable(Of T) 数据类型的修订,但是发布的代码仍然在 Nullable 元素为 Null 时对其进行序列化 - 尽管没有“xs:nil='true'”属性。
I needed to force the serializer to drop the tag completely so I simply implemented IXmlSerializable on the structure (this is in VB but you get the picture):
我需要强制序列化程序完全删除标签,所以我只是在结构上实现了 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
I prefer this method to using the (foo)Specified pattern as that requires adding bucket loads of redundant properties to my objects, whereas using the new Nullable type just requires the retyping of the properties.
我更喜欢这种方法而不是使用 (foo)Specified 模式,因为这需要向我的对象添加冗余属性的桶负载,而使用新的 Nullable 类型只需要重新键入属性。