为什么序列化时会出现“System.StackOverflowException未处理”exception?
我正在尝试序列化以下类:
[Serializable()] public class BindingNode : IEnumerable { public BindingNode() { } IEnumerator IEnumerable.GetEnumerator() { throw new NotImplementedException(); } public IEnumerator GetEnumerator() { throw new NotImplementedException(); } public void Add(BindingNode item) { throw new NotImplementedException(); } }
这最初是一个ICollection而不是IEnumerable,但我尽可能多地删除了我的代码,只保留导致错误的原因。 这是发生exception的代码:
private void button1_Click(object sender, EventArgs e) { BindingNode node = new BindingNode(); if (saveFileDialog1.ShowDialog() == DialogResult.OK) { Stream stream = File.Open(saveFileDialog1.FileName, FileMode.Create); XmlSerializer xmlFormatter = new XmlSerializer(node.GetType()); xmlFormatter.Serialize(stream, node); stream.Close(); } }
XMLSerializer的默认行为是打一个循环,因为作为尝试如何序列化BindingNode
,它然后试图弄清楚如何序列化IEnumerable
,并且这样做它试图弄清楚如何序列化一个BindingNode
。
没有什么可说的,你不能让BindingNode
实现IEnumerable
,只是默认的XMLSerializer行为不起作用。
如果您实现IXmlSerializable,那么您自己控制序列化。 既然您已经知道了BindingNode的结构,那么您就不必在运行时解决这个问题! 如果你有一个非循环图的保证(它不可能有一个自己的祖先BindingNode),那么这是微不足道的:
public void WriteXml(XmlWriter writer) { writer.WriteStartElement("BindingNode"); //More stuff here. foreach(BindingNode contained in this) contained.WriteXml(writer); writer.WriteEndElement(); }
如果图形可以通过循环,它只是稍微复杂一点,你需要能够代替编写包含所有细节的元素,编写一个引用已经序列化到流的节点的元素,否则实际写作会永远持续下去,如果你很幸运,你很快会遇到堆栈溢出的不同原因(如果你运气不好,程序会先将文件的gigs和gigs首先写入磁盘,然后点击它)。
public int SomeSortOfUniqueID { get { //guess what this property has to do! } } public void WriteXml(XmlWriter writer) { WriteXml(writer, new HashSet()); } private void WriteXml(XmlWriter writer, HashSet alreadyWritten) { if(alreadyWritten.Add(this)) { writer.WriteStartElement("BindingNode"); writer.WriteAttributeString("uniqueID", SomeSortOfUniqueID.ToString()); //More stuff here. foreach(BindingNode contained in this) contained.WriteXml(writer, alreadyWritten); writer.WriteEndElement(); } else { //we need to reference a node already mentioned in the document. writer.WriteStartElement("BindingNode"); writer.WriteAttributeString("refID", SomeSortOfUniqueID.ToString()); writer.WriteEndElement(); } }
当然,您还必须实现ReadXml()以再次解析XML。
这将是你的问题: BindingNode : IEnumerable
这将是递归的,你将绑定StackOverFlowException
。 通常人们会创建两个类。
单class:
public class BindingNode { /*..*/ }
集体类:
public class BindingNodeCollection : IEnumerable { /*..*/ }
这种方法通常也会增加内聚力并满足单一责任原则(SRP)。 它是通过分开音乐会来实现的。 集合逻辑放在集合类中,然后原始类执行它想要执行的操作。