在我们的项目中,我们广泛使用 XmlSerializer。偶然我发现了一个没有无参数构造函数的类。我认为这一定会破坏序列化过程,但事实并非如此。
通过调查这个问题,我发现 XmlSerializer 在序列化/反序列化时表现得很奇怪IE可枚举:
- 可枚举的所有元素均已序列化
- 该类需要实现添加(对象) method
- 它忽略此类中可能存在的所有其他属性。
- 它使用此属性调用 getter 并重用返回的实例进行序列化(这允许 XmlSerializer 无需无参数构造函数即可工作)。
请看下面的示例。有趣的部分是 ODD1、ODD2。请注意,good5 和 good6 是假的,而我期望它们是真的。
这种行为有原因吗?
在手动实现 IXmlSerialized 时,是否可以让 XmlSerializer 重用属性返回的实例进行反序列化?
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
namespace Test
{
public static class Program
{
public static void Main()
{
HostingClass host = new HostingClass();
host.AutomaticSerialization.StringProperty = "AUTO";
host.SelfImplementedSerialization.StringProperty = "SELF";
bool good1 = host.AutomaticSerialization.FromConstructor == "PARAMETER";
bool good2 = host.SelfImplementedSerialization.FromConstructor == "PARAMETER";
bool good3 = host.AutomaticSerialization.StringProperty == "AUTO";
bool good4 = host.SelfImplementedSerialization.StringProperty == "SELF";
XmlSerializer serializer = new XmlSerializer(typeof(HostingClass));
using (StringWriter sw = new StringWriter())
{
serializer.Serialize(sw, host);
using (StringReader sr = new StringReader(sw.ToString()))
{
host = (HostingClass)serializer.Deserialize(sr);
}
}
bool good5 = host.AutomaticSerialization.FromConstructor == null; //is false
bool good6 = host.AutomaticSerialization.StringProperty == "AUTO"; //is false
bool good7 = host.SelfImplementedSerialization.FromConstructor == null;
bool good8 = host.SelfImplementedSerialization.StringProperty == "SELF";
}
}
public class HostingClass
{
private SelfImplementedSerialization _selfImplementedSerialization;
public SelfImplementedSerialization SelfImplementedSerialization
{
get
{
return _selfImplementedSerialization
?? (_selfImplementedSerialization = new SelfImplementedSerialization("PARAMETER"));
}
set { _selfImplementedSerialization = value; }
}
private AutomaticSerialization _automaticSerialization;
public AutomaticSerialization AutomaticSerialization
{
get
{
return _automaticSerialization
?? (_automaticSerialization = new AutomaticSerialization("PARAMETER")); //the returned object is used while deserializing
}
set { _automaticSerialization = value; }
}
}
public class SelfImplementedSerialization : IXmlSerializable, IEnumerable<int>
{
public SelfImplementedSerialization() { }
public SelfImplementedSerialization(string parameter)
{
FromConstructor = parameter;
}
public string StringProperty { get; set; }
[XmlIgnore]
public string FromConstructor { get; set; }
public void ReadXml(XmlReader reader)
{
reader.ReadStartElement();
StringProperty = reader.ReadElementString("StringProperty");
reader.ReadEndElement();
}
public void WriteXml(XmlWriter writer)
{
writer.WriteElementString("StringProperty", StringProperty);
}
public IEnumerator<int> GetEnumerator()
{
yield return 1;
yield return 2;
}
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
public XmlSchema GetSchema() { return null; }
}
public class AutomaticSerialization : IEnumerable<int>
{
//ODD1: Serialization possible w/o public parameterless constructor
//public AutomaticSerialization() {}
public AutomaticSerialization(string parameter)
{
FromConstructor = parameter;
}
//ODD2: Element not serialized, only the IEnumerable Interface is serialized
[XmlElement("SP")]
public string StringProperty { get; set; }
[XmlIgnore]
public string FromConstructor { get; set; }
public IEnumerator<int> GetEnumerator()
{
yield return 1;
yield return 2;
}
public void Add(object o)
{
//requirement of XmlSerializer when serializing IEnumerables
}
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
}
}
出现这种行为的原因是它一直都是这样工作的。
From XmlSerializer 类 http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer.aspx:
Note
The XmlSerializer
给予特别的
对实施类的处理IEnumerable
or ICollection
。一类
实现IEnumerable
必须
实现一个公共 Add 方法
采用单个参数。添加
方法的参数必须相同
类型为从返回的Current
返回值的属性GetEnumerator
,或该类型之一
基地。一个实现的类ICollection
(例如CollectionBase
)
此外IEnumerable
必须有一个
公共项目索引属性(索引器
在 C# 中),它接受一个整数,并且它
必须具有公共 Count 属性
类型整数。添加参数
方法必须与 is 类型相同
从 Item 属性返回,或者
该类型的基地之一。上课用
实施ICollection
,值到
被序列化是从检索
索引 Item 属性,而不是通过调用GetEnumerator
.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)