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