#1 和#2 的基本区别在于它们生成不同的XML Schemas。如果您希望将某个成员从您的类型架构中排除,请使用[XmlIgnore]。如果您希望有条件地包含成员,请使用ShouldSerializeXXX() 或XXXSpecified。 (最后,如this answer 所述,选项#3 中的[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() 的源代码以证明它始终返回false。因此Name 将出现在版本#2 的模式中,尽管实际上从未出现过。如果您随后创建一个 Web 服务并使用 WSDL 发布您的架构(或者只是手动使它们可用),将为这两种类型生成不同的客户端——一种没有Name 成员,另一种有。
当所讨论的属性是不可为空的值类型时,可能会产生额外的复杂性。考虑以下三个版本的Item。首先,一个无条件包含 value 属性的版本:
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 值的成员,但对于不可为空的值成员没有类似的逻辑。因此,情况#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 和ShouldSerialize*() vs *Specified Conditional Serialization Pattern。
这是主要区别,但也有次要区别可能会影响您的选择:
[XmlIgnore] 不能在派生类中被覆盖,但ShouldSerializeXXX() 在标记为虚拟时可以;示例见here。
-
如果一个成员不能被XmlSerializer 序列化,例如,它引用了lacks a parameterless constructor 的类型,那么用[XmlIgnore] 标记该成员将允许序列化包含类型 - 同时添加一个@987654377 @ 将不允许包含类型被序列化,因为如前所述 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 和protobuf-net。
如 cmets 中所述,在 Visual Studio 中重命名条件序列化属性不会自动重命名相应的 ShouldSerializeXXX() 方法名称,从而导致潜在的维护问题。