JNY*_*ger 19 .net c# serialization xml-serialization xmlserializer
我知道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);
}
Run Code Online (Sandbox Code Playgroud)
dbc*_*dbc 32
的的意图{propertyName}Specified模式是记录在XML架构绑定支持:的minOccurs属性绑定的支持.添加它是为了支持XSD架构元素,其中:
<element>元素涉及.在这种情况下,xsd.exe /classes将自动生成(或者您可以手动生成)与schema元素同名的属性和一个{propertyName}Specifiedboolean get/set属性,该属性跟踪XML中是否遇到该元素,并应序列化为XML. 如果遇到该元素,{propertyName}Specified则设置为true,否则false.因此,反序列化的实例可以确定该属性是否在原始XML中未设置(而不是显式设置为其默认值).
对于模式生成也实现了逆.如果使用与上述模式匹配的一对属性定义C#类型,则使用xsd.exe生成相应的XSD文件,将相应的适当minOccurrs添加到模式中.例如,给定以下类型:
public class ExampleClass
{
[XmlElement]
public decimal Something { get; set; }
[XmlIgnore]
public bool SomethingSpecified { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
将生成以下架构,反之亦然:
<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>
Run Code Online (Sandbox Code Playgroud)
请注意,虽然xsd.exe仅记录为自动生成{propertyName}Specified值类型属性的属性,XmlSerializer但在手动使用参考类型属性时将遵循该模式.
你可能会问,为什么在这种情况下xsd.exe不绑定Nullable<T>?也许是因为:
xsi:nil="true"属性.请参阅Xsi:nil属性绑定支持.您需要了解这种模式,因为xsd.exe有时会自动为您生成它,但是属性与其Specified属性之间的交互很奇怪并且容易产生错误.您可以填写类中的所有属性,然后序列化为XML并丢失所有内容,因为您还没有设置相应的Specified属性true.这个"问题"不时出现在这里,例如看到这个问题或者这个问题.
使用此模式的另一个"问题"是,如果您需要使用不支持此模式的序列化程序序列化您的类型,您可能希望在序列化期间手动抑制此属性的输出,并且可能需要在反序列化期间手动设置它.由于每个序列化程序可能都有自己的自定义机制来抑制属性(或根本没有机制!),这样做会随着时间的推移变得越来越繁重.
(最后,我有点惊讶你的MyPropertySpecified工作没有setter成功.我似乎记得.Net 2.0的一个版本,其中一个丢失的{propertyName}Specifiedsetter会导致异常被抛出.但它在以后的版本中不再可重现,并且我没有2.0测试.所以这可能是第三个问题.)
Windows窗体控件ShouldSerialize{PropertyName}()中的" 属性"中记录了对该方法的支持:使用ShouldSerialize和Reset方法定义默认值.正如您所看到的,文档位于MSDN的Windows窗体部分而不是该XmlSerializer部分,因此它实际上是半隐藏功能.我不知道为什么支持这种方法和Specified属性都存在于XmlSerializer. ShouldSerialize是在.Net 1.1中引入的,我相信在.Net 2.0中添加了MinOccurs绑定支持,所以早期的功能可能并不完全满足xsd.exe开发团队的需求(或品味)?
因为它是一种方法而不是属性,它缺乏模式的"陷阱" {propertyName}Specified.它似乎在实践中更受欢迎,并已被其他序列化器采用,包括:
那么,使用哪种模式?
如果自动为您xsd.exe生成{propertyName}Specified属性,或者您的类型需要跟踪XML文件中是否出现特定元素,或者您需要自动生成的XSD来指示某个值是可选的,请使用此模式并注意"陷阱".
否则,请使用该ShouldSerialize{PropertyName}()模式.它的陷阱较少,可能会得到更广泛的支持.
为了添加@dbc的非常详细的答案,我在管理派生类中的序列化时遇到了一个问题。在我的情况下,我有一个基类和一个派生类,其中的Prop属性被覆盖。
public class BaseClass
{
public virtual string Prop {get; set;}
}
public class Derived: BaseClass
{
public string Comp1 {get; set;}
public string Comp2 {get; set;}
public override string Prop {get => Comp1 + Comp2; set {}}
}
Run Code Online (Sandbox Code Playgroud)
由于Prop在派生类属性进行计算,对于Derived类,我想序列化Comp1和Comp2,但不会Prop。事实证明,在类中的XmlIgnore属性上设置属性不起作用,并且无论如何都要序列化。PropDerivedProp
我也尝试在类中添加一个ShouldSerializeProp方法和一个PropSpecified属性Derived,但是都没有用。我尝试设置断点以查看是否调用了断点,而未调用断点。
事实证明,XmlSerializer正在查看Prop属性在类层次结构中首次出现的原始类,以决定是否序列化属性。为了能够在派生类中控制序列化,首先我必须virtual ShouldSerializeProp在Base类中添加一个。
public class Base
{
.....
public virtual bool ShouldSerializeProp() {return true;}
}
Run Code Online (Sandbox Code Playgroud)
然后,我可以ShouldSerializeProp在Derived该类中重写并返回false。
public class Derived: Base
{
.....
public override bool ShouldSerializeProp() {return false;}
}
Run Code Online (Sandbox Code Playgroud)
这种模式允许不同的派生类从要序列化的父类中选择哪些属性。希望这可以帮助。
| 归档时间: |
|
| 查看次数: |
7851 次 |
| 最近记录: |