我知道ShouldSerialize* 模式和 *Specified模式以及它们是如何工作的,但是这两者之间有什么区别吗?
当某些东西应该有条件地序列化时,使用一种方法与使用另一种方法是否存在“陷阱”?
这个问题专门针对XmlSerializer
的用法,但也欢迎提供有关这个主题的一般信息。
关于这个主题的信息非常少,所以这可能是因为它们执行完全相同的目的,这是一个样式选择。然而,似乎很奇怪,.NET实现者会通过反射来分析类,并寻找其中一个/两个模式来确定生成的序列化程序的行为,因为它减慢了序列化程序的生成,除非它只是一个向后兼容的工件。
**EDIT:**对于不熟悉这两种模式的人,如果*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);
}
2条答案
按热度按时间ijxebb2r1#
{propertyName}Specified
模式的意图在XML Schema Binding Support: MinOccurs Attribute Binding Support中有文档记录,添加它是为了支持XSD模式元素,其中:<element>
**元素。*最小发生次数为零。
*maxOccurs属性指示单个示例。
在这种情况下,
xsd.exe /classes
将自动生成(或者您可以手动生成)与架构元素同名的属性和{propertyName}Specified
布尔get/set属性 ,该属性跟踪在XML中是否遇到该元素以及是否应该将其序列化回XML。 如果遇到该元素,则将{propertyName}Specified
设置为true
,因此,反序列化后的示例可以确定该属性在原始XML中是否未设置(而不是显式设置为其默认值)。架构生成也实现了相反的过程。如果您定义了一个C#类型,该类型具有与上述模式匹配的一对属性,然后使用
xsd.exe
生成相应的XSD文件,则会向架构添加适当的minOccurrs
。例如,给定以下类型:将生成以下架构,反之亦然:
请注意,虽然
xsd.exe
仅用于为值类型属性自动生成{propertyName}Specified
属性,但当手动用于引用类型属性时,XmlSerializer
将遵循该模式。您可能会问,为什么
xsd.exe
在这种情况下不绑定到Nullable<T>
?可能是因为:xsi:nil="true"
属性。请参见Xsi:nil Attribute Binding Support。您需要注意这种模式,因为
xsd.exe
有时会自动为您生成它,但是属性和它的Specified
属性之间的交互很奇怪,容易产生bug。然后序列化为XML并丢失 * 所有内容 *,因为您还没有将相应的Specified
属性设置为true
。参见例如X1 E3 F1 X或X1 E4 F1 X。此模式的另一个“陷阱”是,如果您需要使用不支持此模式的序列化程序序列化类型,则可能希望在序列化期间手动取消此属性的输出,并且可能需要在反序列化期间手动设置它。由于每个序列化程序都可能有自己的自定义机制来取消属性(或者根本没有机制!),随着时间的推移,这样做会变得越来越繁重。
(最后,我对
MyPropertySpecified
在没有setter的情况下也能成功工作感到有点惊讶。我好像记得.Net 2.0的一个版本中,缺少{propertyName}Specified
setter会导致抛出异常。但它在以后的版本中不再可重现,而且我也没有2.0可供测试。所以这可能是第三个问题。)Properties in Windows Forms Controls: Defining Default Values with the ShouldSerialize and Reset Methods中记录了对
ShouldSerialize{PropertyName}()
方法的支持,正如您所看到的,该文档位于MSDN的Windows窗体部分,而不是XmlSerializer
部分,因此,实际上,我不知道为什么在XmlSerializer
中同时存在对这个方法和Specified
属性的支持。ShouldSerialize
是在.Net 1.1中引入的,我 * 相信 * MinOccurs绑定支持是在.Net 2.0中添加的,所以也许早期的功能并不完全满足xsd.exe
开发团队的需求(或口味)?因为它是一个方法而不是属性,所以它没有
{propertyName}Specified
模式中的“陷阱”。它在实践中似乎也更受欢迎,并已被其他序列化程序采用,包括:那么,该使用哪种模式呢?
1.如果
xsd.exe
为您自动生成{propertyName}Specified
属性,或者您的类型需要跟踪特定元素是否出现在XML文件中,或者您需要自动生成的XSD来指示某个值是可选的,那么请使用此模式并注意“陷阱”。1.否则,请使用
ShouldSerialize{PropertyName}()
模式,它的缺陷较少,可能得到更广泛的支持。ufj5ltwl2#
为了补充@dbc给出的非常详细的答案,我遇到了一个在派生类中管理序列化的问题,在我的情况下,我有一个基类和一个派生类,其中
Prop
属性被覆盖。由于派生类中的
Prop
属性是计算出来的,所以对于Derived
类,我想序列化Comp1
和Comp2
,但不序列化Prop
。结果是,在Derived
类中的Prop
属性上设置XmlIgnore
属性不起作用,并且Prop
无论如何都会被序列化。我还尝试在
Derived
类中添加一个ShouldSerializeProp
方法和一个PropSpecified
属性,但都不起作用。我尝试设置断点,看看它们是否被调用。原来
XmlSerializer
是在查看Prop
属性在类层次结构中第一次出现的原始类,以决定是否序列化属性。为了能够控制派生类中的序列化,首先我必须在Base
类中添加virtual ShouldSerializeProp
。然后我可以覆盖
Derived
类中的ShouldSerializeProp
并返回false。这个模式允许不同的派生类选择它们序列化父类中的哪些属性。希望这能有所帮助。