ShouldSerialize *()与*指定的条件序列化模式
我知道ShouldSerialize 模式和 Specified模式以及它们的工作方式,但是两者之间有什么区别吗?
当某些事情应该有条件地序列化时,是否存在使用一种方法相对于另一种方法的“陷阱”?
此问题特定于的用法XmlSerializer
,但也欢迎提供有关此主题的一般信息。
关于此主题的信息很少,这可能是因为它们执行的目的完全相同,这是一种样式选择。但是,.NET实现者会通过反射分析类并查找任何一种/两种模式来确定所生成的序列化器的行为,这似乎很奇怪,因为除非它只是一个向后兼容的构件,否则它会减慢序列化器的生成。
对于那些不熟悉这两种模式的人,如果该*Specified
属性或ShouldSerialize*
方法返回true,则该属性被序列化。
public string MyProperty { get; set; }//*Specified Pattern
[XmlIgnore]
public bool MyPropertySpecified { get{ return !string.IsNullOrWhiteSpace(this.MyProperty); } }
//ShouldSerialize* Pattern
public bool ShouldSerializeMyProperty()
{
return !string.IsNullOrWhiteSpace(this.MyProperty);
}
回答:
XML模式绑定支持中{propertyName}Specified
记录了该模式的意图:MinOccurs属性绑定支持。添加它是为了支持XSD架构元素,其中:
- 该 元素是参与。
- 为零。
- 该 属性使然一个实例。
- 数据类型转换为值类型。
在这种情况下,xsd.exe /classes
将自动生成(或您可以手动生成)与架构元素同名的属性,以及一个{propertyName}Specified
布尔型的get
/ set属性 ,该 属性 跟踪该元素是否在XML中遇到,并应序列化回XML。
如果遇到元素,{propertyName}Specified
则设置为true
,否则设置为false
。因此,反序列化的实例可以确定属性是否在原始XML中未设置(而不是显式设置为默认值)。
逆也用于模式生成。如果您定义具有一对与上述模式匹配的属性的C#类型,然后用于xsd.exe
生成相应的XSD文件,minOccurrs
则会将适当的XSD文件添加到架构中。例如,给定以下类型:
public class ExampleClass{
[XmlElement]
public decimal Something { get; set; }
[XmlIgnore]
public bool SomethingSpecified { get; set; }
}
将生成以下架构,反之亦然:
<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="ExampleClass" nillable="true" type="ExampleClass" />
<xs:complexType name="ExampleClass">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" name="Something" type="xs:decimal" />
</xs:sequence>
</xs:complexType>
</xs:schema>
请注意,虽然xsd.exe
只记录了{propertyName}Specified
为值类型属性自动生成属性的情况,XmlSerializer
但是当手动将其用于引用类型属性时,将遵循该模式。
您可能会问,为什么在这种情况下xsd.exe
不绑定到Nullable<T>
?可能是因为:
- 空变量用于支持
xsi:nil="true"
属性。请参阅Xsi:nil属性绑定支持。 - 在.Net 2.0之前没有引入可空变量,所以也许将其用于此目的为时已晚?
您需要了解这种模式,因为xsd.exe
有时会自动为您生成该模式,但是属性与其Specified
属性之间的交互很奇怪,并且容易产生错误。您可以填充类中的所有属性,然后序列化为XML并丢失
所有内容,
因为您也没有将相应的Specified
属性设置为true
。这里有时会出现这个“陷阱”,例如,也可以参见这个问题或这个问题。
这种模式的另一个“陷阱”是,如果您需要使用不支持该模式的序列化程序来序列化类型,则 要在序列化过程中手动抑制此属性的输出,并且
需要在反序列化过程中手动进行设置。由于每个序列化程序可能都有自己的自定义机制来抑制属性(或者根本没有机制!),随着时间的推移,这样做会变得越来越繁重。
(最后,对于MyPropertySpecified
没有设置器的情况下您的工作成功,我感到有些惊讶。我似乎想起了.Net
2.0的一个版本,在该版本中,缺少{propertyName}Specified
设置器会导致抛出异常。但是在更高版本中,它不再可复制,我没有要测试的2.0。所以这可能是第三个陷阱。
Windows窗体控件的“属性”中ShouldSerialize{PropertyName}()
记录了对该方法的支持:使用ShouldSerialize和Reset方法定义默认值。如您所见,文档位于MSDN的Windows窗体部分而不是该XmlSerializer
部分,因此实际上是半隐藏功能。我不知道为什么支持此方法和Specified
属性都存在于中XmlSerializer
。
ShouldSerialize
是在.Net 1.1中引入的,我 相信 Min.ccurs绑定支持是在.Net
2.0中添加的,所以也许早期的功能不能完全满足xsd.exe
开发团队的需求(或品味)?
因为它是方法而不是属性,所以它缺少模式的“陷阱”
{propertyName}Specified
。它在实践中似乎也更流行,并且已被其他序列化器采用,包括:
- Json.NET
- protobuf-net(声称支持这两种模式。)
那么,使用哪种模式?
如果自动为您
xsd.exe
生成{propertyName}Specified
属性,或者您的类型需要跟踪XML文件中是否出现了特定元素,或者您需要自动生成的XSD来指示某个值是可选的,请使用此模式并当心“陷阱”。否则,请使用该
ShouldSerialize{PropertyName}()
模式。它的陷阱更少,并且可能得到更广泛的支持。
以上是 ShouldSerialize *()与*指定的条件序列化模式 的全部内容, 来源链接: utcz.com/qa/424311.html