В нашем проекте мы широко используем XmlSerializer. Случайно я нашел класс без конструктора без параметров. Я думал, что это должно нарушить процесс сериализации, но это не так.
Исследуя эту проблему, я обнаружил, что XmlSerializer ведет себя странно при сериализации / десериализации IEnumerable :
- Все элементы перечислимого сериализуются
- Класс необходим для реализации Add (объект) метод
- Он игнорирует все другие свойства, которые могут быть в этом классе.
- Он вызывает метод получения с этим свойством и повторно использует возвращенный экземпляр для сериализации (что позволяет XmlSerializer работать без конструктора без параметров).
Пожалуйста, посмотрите на следующий пример. Интересными частями являются ODD1, ODD2. Обратите внимание, что good5 и good6 ложные, когда я ожидал, что они будут правдой.
Есть ли причина для такого поведения?
Можно ли заставить XmlSerializer повторно использовать экземпляр, возвращаемый свойством для десериализации при реализации IXmlSerializable вручную?
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(); }
}
}