何时使用 ShouldSerializeXXX 与 XmlIgnoreAttribute 进行 XML 序列化
When to use ShouldSerializeXXX vs. XmlIgnoreAttribute for XML serialization
我一直在寻找在 xml 序列化和反序列化期间忽略 class 的 属性 的示例。我找到了三种不同的方法,但不知道什么时候应该使用它们。我特别感兴趣的是,哪个更适合 XmlSerializer
。
-
public class Item
{
[XmlIgnore]
public string Name { get; set; }
}
以ShouldSerialize...
开头的方法
public class Item
{
public string Name { get; set; }
public bool ShouldSerializeName()
{
return false;
}
}
-
public class Item
{
[NonSerialized]
public string Name { get; set; }
}
在 Whosebug and msdn 上有一些关于 XmlIgnoreAttribtue
和 NonSerializedAttribute
之间的区别的解释,我无法找到有关何时使用 XmlIgnoreAttribtue
以及何时使用的信息ShouldSerializeXXX
模式。我用 XmlSerializer 尝试了它们,它们都按预期工作。
#1 和#2 之间的基本区别是它们在选项 #3 中生成不同的 XML Schemas. If you want a member to be excluded from your type's schema, use [XmlIgnore]
. If you want a member to be included conditionally, use ShouldSerializeXXX()
or XXXSpecified
. (Finally, as stated in this answer, [NonSerialized]
被 XmlSerializer
忽略。)
要查看#1 和#2 之间的区别,您可以使用 xsd.exe
为您的类型生成架构。以下模式是为版本 #1 生成的,并且完全省略了 Name
成员:
<xs:complexType name="Item" />
而#2 的以下内容有条件地包括 Name
成员:
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" name="Name" type="xs:string" />
</xs:sequence>
差异的出现是因为 XmlSerializer
和 xsd.exe
都执行 静态类型分析 而不是 动态代码分析 .这两个工具都不能确定案例 #2 中的 Name
属性 将始终被跳过,因为这两个工具都不会尝试反编译 ShouldSerializeName()
的源代码以证明它总是 returns false
。因此 Name
将出现在版本 #2 的模式中,尽管实际上从未出现过。如果您随后创建一个 Web 服务并使用 WSDL 发布您的模式(或者只是手动使它们可用),将为这两种类型生成不同的客户端——一种没有 Name
成员,一种有.
当所讨论的 属性 是不可空值类型时,会出现额外的复杂性。考虑以下三个版本的 Item
。首先,无条件包含值 属性:
的版本
public class Item
{
public int Id { get; set; }
}
生成以下架构,Id
始终存在:
<xs:complexType name="Item">
<xs:sequence>
<xs:element minOccurs="1" maxOccurs="1" name="Id" type="xs:int" />
</xs:sequence>
</xs:complexType>
其次,无条件排除值属性的版本:
public class Item
{
[XmlIgnore]
public int Id { get; set; }
}
生成完全省略 Id
属性 的以下架构:
<xs:complexType name="Item" />
最后是一个有条件排除值的版本 属性:
public class Item
{
public int Id { get; set; }
public bool ShouldSerializeId()
{
return false;
}
}
生成以下架构 Id
仅有条件地存在:
<xs:complexType name="Item">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" name="Id" type="xs:int" />
</xs:sequence>
</xs:complexType>
Schema #2 符合预期,但请注意 #1 和 #3 之间存在差异:第一个具有 minOccurs="1"
,而第三个具有 minOccurs="0"
。出现差异是因为 XmlSerializer
是 documented 默认情况下跳过具有 null
值的成员,但对于不可为 null 的值成员没有类似的逻辑。因此,案例 #1 中的 Id
属性 将始终被序列化,因此 minOccurs="1"
在架构中指示。只有开启条件序列化才会生成minOccurs="0"
。如果第三个模式依次用于客户端代码生成,则会在自动生成的代码中添加一个 IdSpecified
属性 以跟踪是否实际遇到了 Id
属性反序列化期间:
public partial class Item {
private int idField;
private bool idFieldSpecified;
/// <remarks/>
public int Id {
get {
return this.idField;
}
set {
this.idField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlIgnoreAttribute()]
public bool IdSpecified {
get {
return this.idFieldSpecified;
}
set {
this.idFieldSpecified = value;
}
}
}
有关绑定到条件序列化值成员的更多详细信息,请参阅 XML Schema Binding Support: MinOccurs Attribute Binding Support and 。
这是主要区别,但也有可能影响您选择的次要区别:
[XmlIgnore]
无法在派生的 class 中被覆盖,但 ShouldSerializeXXX()
可以在标记为虚拟时被覆盖;有关示例,请参阅 here。
如果一个成员不能被XmlSerializer
序列化,因为,例如,它指的是一个lacks a parameterless constructor的类型,那么用[XmlIgnore]
标记该成员将允许包含类型被序列化——添加 ShouldSerializeXXX() { return false; }
将不允许包含类型被序列化,因为如前所述 XmlSerializer
仅执行静态类型分析。例如。以下:
public class RootObject
{
// This member will prevent RootObject from being serialized by XmlSerializer despite the fact that the ShouldSerialize method always returns false.
// To make RootObject serialize successfully, [XmlIgnore] must be added.
public NoDefaultConstructor NoDefaultConstructor { get; set; }
public bool ShouldSerializeNoDefaultConstructor() { return false; }
}
public class NoDefaultConstructor
{
public string Name { get; set; }
public NoDefaultConstructor(string name) { this.Name = name; }
}
不能被XmlSerializer
序列化。
[XmlIgnore]
特定于 XmlSerializer
,但 ShouldSerializeXXX()
被其他序列化器使用,包括 Json.NET and protobuf-net.
如评论中所述,在 Visual Studio 中重命名条件序列化的 属性 不会自动重命名相应的 ShouldSerializeXXX()
方法名称,从而导致潜在的维护问题路.
我一直在寻找在 xml 序列化和反序列化期间忽略 class 的 属性 的示例。我找到了三种不同的方法,但不知道什么时候应该使用它们。我特别感兴趣的是,哪个更适合 XmlSerializer
。
-
public class Item { [XmlIgnore] public string Name { get; set; } }
以
ShouldSerialize...
开头的方法public class Item { public string Name { get; set; } public bool ShouldSerializeName() { return false; } }
-
public class Item { [NonSerialized] public string Name { get; set; } }
在 Whosebug and msdn 上有一些关于 XmlIgnoreAttribtue
和 NonSerializedAttribute
之间的区别的解释,我无法找到有关何时使用 XmlIgnoreAttribtue
以及何时使用的信息ShouldSerializeXXX
模式。我用 XmlSerializer 尝试了它们,它们都按预期工作。
#1 和#2 之间的基本区别是它们在选项 #3 中生成不同的 XML Schemas. If you want a member to be excluded from your type's schema, use [XmlIgnore]
. If you want a member to be included conditionally, use ShouldSerializeXXX()
or XXXSpecified
. (Finally, as stated in this answer, [NonSerialized]
被 XmlSerializer
忽略。)
要查看#1 和#2 之间的区别,您可以使用 xsd.exe
为您的类型生成架构。以下模式是为版本 #1 生成的,并且完全省略了 Name
成员:
<xs:complexType name="Item" />
而#2 的以下内容有条件地包括 Name
成员:
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" name="Name" type="xs:string" />
</xs:sequence>
差异的出现是因为 XmlSerializer
和 xsd.exe
都执行 静态类型分析 而不是 动态代码分析 .这两个工具都不能确定案例 #2 中的 Name
属性 将始终被跳过,因为这两个工具都不会尝试反编译 ShouldSerializeName()
的源代码以证明它总是 returns false
。因此 Name
将出现在版本 #2 的模式中,尽管实际上从未出现过。如果您随后创建一个 Web 服务并使用 WSDL 发布您的模式(或者只是手动使它们可用),将为这两种类型生成不同的客户端——一种没有 Name
成员,一种有.
当所讨论的 属性 是不可空值类型时,会出现额外的复杂性。考虑以下三个版本的 Item
。首先,无条件包含值 属性:
public class Item
{
public int Id { get; set; }
}
生成以下架构,Id
始终存在:
<xs:complexType name="Item">
<xs:sequence>
<xs:element minOccurs="1" maxOccurs="1" name="Id" type="xs:int" />
</xs:sequence>
</xs:complexType>
其次,无条件排除值属性的版本:
public class Item
{
[XmlIgnore]
public int Id { get; set; }
}
生成完全省略 Id
属性 的以下架构:
<xs:complexType name="Item" />
最后是一个有条件排除值的版本 属性:
public class Item
{
public int Id { get; set; }
public bool ShouldSerializeId()
{
return false;
}
}
生成以下架构 Id
仅有条件地存在:
<xs:complexType name="Item">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" name="Id" type="xs:int" />
</xs:sequence>
</xs:complexType>
Schema #2 符合预期,但请注意 #1 和 #3 之间存在差异:第一个具有 minOccurs="1"
,而第三个具有 minOccurs="0"
。出现差异是因为 XmlSerializer
是 documented 默认情况下跳过具有 null
值的成员,但对于不可为 null 的值成员没有类似的逻辑。因此,案例 #1 中的 Id
属性 将始终被序列化,因此 minOccurs="1"
在架构中指示。只有开启条件序列化才会生成minOccurs="0"
。如果第三个模式依次用于客户端代码生成,则会在自动生成的代码中添加一个 IdSpecified
属性 以跟踪是否实际遇到了 Id
属性反序列化期间:
public partial class Item {
private int idField;
private bool idFieldSpecified;
/// <remarks/>
public int Id {
get {
return this.idField;
}
set {
this.idField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlIgnoreAttribute()]
public bool IdSpecified {
get {
return this.idFieldSpecified;
}
set {
this.idFieldSpecified = value;
}
}
}
有关绑定到条件序列化值成员的更多详细信息,请参阅 XML Schema Binding Support: MinOccurs Attribute Binding Support and
这是主要区别,但也有可能影响您选择的次要区别:
[XmlIgnore]
无法在派生的 class 中被覆盖,但ShouldSerializeXXX()
可以在标记为虚拟时被覆盖;有关示例,请参阅 here。如果一个成员不能被
XmlSerializer
序列化,因为,例如,它指的是一个lacks a parameterless constructor的类型,那么用[XmlIgnore]
标记该成员将允许包含类型被序列化——添加ShouldSerializeXXX() { return false; }
将不允许包含类型被序列化,因为如前所述XmlSerializer
仅执行静态类型分析。例如。以下:public class RootObject { // This member will prevent RootObject from being serialized by XmlSerializer despite the fact that the ShouldSerialize method always returns false. // To make RootObject serialize successfully, [XmlIgnore] must be added. public NoDefaultConstructor NoDefaultConstructor { get; set; } public bool ShouldSerializeNoDefaultConstructor() { return false; } } public class NoDefaultConstructor { public string Name { get; set; } public NoDefaultConstructor(string name) { this.Name = name; } }
不能被
XmlSerializer
序列化。[XmlIgnore]
特定于XmlSerializer
,但ShouldSerializeXXX()
被其他序列化器使用,包括 Json.NET and protobuf-net.如评论中所述,在 Visual Studio 中重命名条件序列化的 属性 不会自动重命名相应的
ShouldSerializeXXX()
方法名称,从而导致潜在的维护问题路.