【发布时间】:2016-12-09 08:54:47
【问题描述】:
我有一个只能使用自定义 XML 序列化进行序列化的类,该类将用作使用基本序列化的更大系统中某些类的属性。我无法将整个系统转换为自定义序列化,因为它很大,并且将来可能包含使用基本序列化的第三方模块。
我的第一个问题是这是否被允许。我在 MSDN 上看不到任何内容说不允许从基本序列化对象引用自定义序列化对象,如果不能,这似乎是对代码可移植性的严重限制。然而,该站点上的较早答案似乎表明您可能无法做到(海报说“不幸的是,您不能真正混合和匹配序列化;一旦实现 IXmlSerializable,您就拥有一切”)尽管我认为他指的是在一个类中混合和匹配,这显然是你做不到的。 (看: Mixing custom and basic serialization?)
所以假设这实际上是允许的,我的问题是,每当主系统中的一个类实现一个包含两个或多个具有自定义序列化的类的对象的 List 时,它就会失败。
有趣的是,失败只发生在反序列化时,并且只发生在对这样一个对象的引用不止一个时。更有趣的是,即使列表出现在依赖链的更上游,它也会以同样的方式失败(例如,列表包含普通对象,其中包含普通对象,其中可能包含使用自定义序列化的对象)。
我写了一个小测试程序来演示最简单的情况,如下所示。
所以我的问题是:
- 实际上是否允许引用自定义序列化对象 基本序列化的?
- 如果是,我是不是在做傻事?
- 如果不是,这是一个已知的错误吗?
测试程序注意事项: 数据类结构非常简单,由 BasicXml 类(使用基本序列化)和 CustomXml 类(使用自定义序列化)组成。 BasicXml 包含一个 CustomXml 列表。 另一个类包含测试,它是自立的。只需实例化并运行 RunTests()。
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Schema;
using System.Xml.Serialization;
namespace AdHocTests
{
[Serializable]
public class BasicXml
{
public List<CustomXml> TestList { get; set; }
}
[Serializable]
public class CustomXml : IXmlSerializable
{
public CustomXml() { }
public CustomXml(string name)
{
Name = name;
}
public string Name { get; set; }
public void ReadXml(XmlReader reader)
{
Name = reader.ReadString();
}
public void WriteXml(XmlWriter writer)
{
writer.WriteString(Name);
}
public XmlSchema GetSchema()
{
return null; // I have removed this code for clarity
}
}
public class MixedSerializationTest
{
public MixedSerializationTest()
{
_serializer.UnknownElement += UnknownElementHandler;
}
public void RunTests()
{
RunOneTest(makeItFail: false);
RunOneTest(makeItFail: true);
}
private void RunOneTest(bool makeItFail)
{
Debug.Write("\n\nRUNNING TEST THAT WILL " + (makeItFail ? "FAIL" : "PASS") + ":\n\n");
CustomXml c1 = new CustomXml("Hello");
CustomXml c2 = new CustomXml("World");
BasicXml b1 = new BasicXml
{
TestList = makeItFail ? new List<CustomXml> { c1, c2 } : new List<CustomXml> { c1 }
};
XElement xml1 = GetXmlFromObject(b1);
Debug.Write("Serialized XML:\n" + xml1.ToString() + "\n=====\n");
BasicXml b2 = GetObjectFromXml(xml1);
if (_cancelDeserialization) return;
XElement xml2 = GetXmlFromObject(b2);
Debug.Write("Reserialized XML:\n" + xml2.ToString() + "\n=====\n");
}
private XElement GetXmlFromObject(BasicXml obj)
{
using (StringWriter sw = new StringWriter())
{
using (XmlWriter xw = XmlWriter.Create(sw))
{
_serializer.Serialize(xw, obj);
return XElement.Parse(sw.ToString());
}
}
}
private BasicXml GetObjectFromXml(XElement xml)
{
using (StringReader sr = new StringReader(xml.ToString()))
{
XmlWriterSettings settings = new XmlWriterSettings();
using (XmlReader xr = XmlReader.Create(sr))
{
return (BasicXml)_serializer.Deserialize(xr);
}
}
}
private void UnknownElementHandler(object sender, XmlElementEventArgs e)
{
Debug.Write("\n*** Serializer threw an UnknownElement exception ***\n\n");
_cancelDeserialization = true;
}
private XmlSerializer _serializer = new XmlSerializer(typeof(BasicXml));
private bool _cancelDeserialization = false;
}
}
【问题讨论】:
-
请注意,如果 CustomXml 不 实现 IXmlSerializable,它可以工作,这表明您遗漏了一些东西。
-
好minimal reproducible example!我能够立即重现该问题。
-
您好 RamblinRose,移除 IXmlSerializable 接口是将其转回基本序列化而不是自定义的开关,所以是的,它可以工作,因为它已转回正常的基本 + 基本情况。当接口到位时(表示基本+自定义情况)它几乎一直工作,并且总是完美地序列化,这表明代码可能是正确的。只是它在我布置的非常特殊的情况下做出了这种奇怪的事情。
-
感谢您的反馈,dbc
标签: c# xml serialization