我在xml序列化和反序列化期间查找了忽略类属性的示例。我找到了三种不同的方法,但是在应该使用它们时无法弄清楚。我特别感兴趣的是,哪一个更适合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; }
}
如果对stackoverflow和msdn上XmlIgnoreAttribtue
和NonSerializedAttribute
之间的区别有一些解释,我无法找到有关何时使用{{1}的信息当XmlIgnoreAttribtue
模式时。我使用XmlSerializer尝试了它们,并且它们都看到了预期的工作。
答案 0 :(得分:3)
#1和#2之间的基本区别在于它们会生成不同的 XML Schemas 。如果您希望将成员从类型的架构中排除,请使用[XmlIgnore]
。如果您希望有条件地加入成员,请使用ShouldSerializeXXX()
或XXXSpecified
。 (最后,正如this answer中所述,XmlSerializer
会忽略选项#3中的[NonSerialized]
。)
要查看#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
。首先,具有无条件值属性的版本:
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>
架构#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]
标记该成员将允许包含类型要序列化 - 添加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和protobuf-net。
如评论中所述,在Visual Studio中重命名有条件序列化的属性不会自动重命名相应的ShouldSerializeXXX()
方法名称,从而导致潜在的维护问题。