为什么序列化时会出现“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)。 它是通过分开音乐会来实现的。 集合逻辑放在集合类中,然后原始类执行它想要执行的操作。