我正在尝试序列化以下类:
[Serializable()]
public class BindingNode : IEnumerable<BindingNode>
{
public BindingNode()
{
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
public IEnumerator<BindingNode> GetEnumerator()
{
throw new NotImplementedException();
}
public void Add(BindingNode item)
{
throw new NotImplementedException();
}
}
这最初是一个ICollection而不是IEnumerable,但我尽可能多地删除了我的代码,只保留导致错误的原因。这是发生异常的代码:
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();
}
}
答案 0 :(得分:2)
这将是你的问题:BindingNode : IEnumerable<BindingNode>
这将是递归的,你会绑定StackOverFlowException
。通常人们会创建两个类。
单班:
public class BindingNode
{
/*..*/
}
集体类:
public class BindingNodeCollection : IEnumerable<BindingNode>
{
/*..*/
}
这种方法通常也会增加凝聚力并满足单一责任原则(SRP)。它是通过分开音乐会来实现的。集合逻辑放在集合类中,然后原始类执行它想要做的事情。
答案 1 :(得分:2)
XMLSerializer的默认行为是打一个循环,因为作为尝试如何序列化BindingNode
的一部分,它然后试图弄清楚如何序列化IEnumerable<BindingNode>
,并做到这一点它试图弄清楚如何序列化BindingNode
。
没有什么可说的,你不能BindingNode
实现IEnumerable<BindingNode>
,只是默认的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<BindingNode>());
}
private void WriteXml(XmlWriter writer, HashSet<BindingNode> 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。