为什么我得到一个" System.StackOverflowException是未处理"序列化时异常? [英] Why do I get a "System.StackOverflowException was unhandled " exception when serializing?

查看:169
本文介绍了为什么我得到一个" System.StackOverflowException是未处理"序列化时异常?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图序列化以下类:

  [序列化()]
公共类BindingNode:IEnumerable的< BindingNode>
{
    公共BindingNode()
    {
    }

    IEnumerator的IEnumerable.GetEnumerator()
    {
        抛出新的NotImplementedException();
    }

    公众的IEnumerator< BindingNode>的GetEnumerator()
    {
        抛出新的NotImplementedException();
    }

    公共无效添加(BindingNode项)
    {
        抛出新的NotImplementedException();
    }
}
 

这原本是一个ICollection的,而不是一个IEnumerable,但我删除了,就像我能我的code只保留什么原因造成的错误。这里的code其中发生异常:

 私人无效的button1_Click(对象发件人,EventArgs的)
    {
        BindingNode节点=新BindingNode();
        如果(saveFileDialog1.ShowDialog()== DialogResult.OK)
        {
            流流= File.open方法(saveFileDialog1.FileName,FileMode.Create);
            XmlSerializer的xmlFormatter =新的XmlSerializer(node.GetType());
            xmlFormatter.Serialize(流点);
            stream.Close();
        }
    }
 

解决方案

有关XMLSerializer的默认行为是打一个循环,因为作为试图找出如何serialse一个 BindingNode 后,就会试图找出如何连载的的IEnumerable< BindingNode> ,要做到这一点它试图找出如何连载一 BindingNode

还有什么可说的,你不能有 BindingNode 实施的IEnumerable< BindingNode> ,只是默认XMLSerializer的行为是行不通的。

如果您实现IXmlSerializable的,那么你就控制了序列化自己。既然你已经知道BindingNode的结构,你不用上班了这一点,在运行时!如果你一个非循环图的保证(这是不可能有一个BindingNode是它本身的祖先),那么这是微不足道的:

 公共无效中WriteXML(XmlWriter的作家)
{
    writer.WriteStartElement(BindingNode);
    //更多的东西在这里。
    的foreach(包含在此BindingNode)
        contained.WriteXml(作家);
    writer.WriteEndElement();
}
 

如果该图可以由环状的,它只是稍微在更复杂的需要能够代替写入的元素的所有细节包括,你写引用一个节点已经序列化到流的元素,如否则,实际写作那张永远,如果你很幸运,你很快打出了一个堆栈溢出pretty的不同原因(如果你运气不好的节目欢快第一写入一个文件到磁盘的音乐会和演出,然后点击它)。

 公众诠释SomeSortOfUniqueID
{
    得到
    {
        //你猜怎么着这家酒店做的!
    }
}
公共无效中WriteXML(XmlWriter的作家)
{
    中WriteXML(作家,新的HashSet< BindingNode>());
}
私人无效中WriteXML(XmlWriter的作家,HashSet的< BindingNode> alreadyWritten)
{
    如果(alreadyWritten.Add(本))
    {
        writer.WriteStartElement(BindingNode);
        writer.WriteAttributeString(UNIQUEID,SomeSortOfUniqueID.ToString());
        //更多的东西在这里。
        的foreach(包含在此BindingNode)
            contained.WriteXml(作家,alreadyWritten);
        writer.WriteEndElement();
    }
    其他
    {
        //我们需要引用已经文件中提到的节点。
        writer.WriteStartElement(BindingNode);
        writer.WriteAttributeString(REFID,SomeSortOfUniqueID.ToString());
        writer.WriteEndElement();
    }
}
 

当然,你也有实现的ReadXml()来回来解析XML。

I'm trying to serialize the following class:

[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();
    }
}

This was originally an ICollection instead of an IEnumerable, but I removed as much as I could of my code to keep only what caused the error. Here's the code where the exception occurs:

    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();
        }            
    }

解决方案

The default behaviour for XMLSerializer is hitting a loop because as part of trying to work out how to serialse a BindingNode, it then tries to figure out how to serialise an IEnumerable<BindingNode>, and to do that it tries to figure out how to serialise a BindingNode.

There's nothing to say that you can't have BindingNode implement IEnumerable<BindingNode>, just that the default XMLSerializer behaviour isn't going to work.

If you implement IXmlSerializable, then you control the serialisation yourself. Since you already know the structure of a BindingNode, you don't have to work that out at runtime! If you've a guarantee of an acyclic graph (it's impossible to have a BindingNode that is an ancestor of itself), then this is trivial:

public void WriteXml(XmlWriter writer)
{
    writer.WriteStartElement("BindingNode");
    //More stuff here.
    foreach(BindingNode contained in this)
        contained.WriteXml(writer);
    writer.WriteEndElement();
}

If the graph can by cyclic, it's just slightly more complicated in that you need to be able to instead of writing an element with all the details included, that you write an element that references a node already serialised to the stream, as otherwise the actual writing goes on forever and if you're lucky you hit a different cause of a stack overflow pretty soon (if you're unlucky the program merrily writes gigs and gigs of a file to disk first, and then hits it).

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();
    }
}

Of course, you'll also have to implement ReadXml() to parse the XML back again.

这篇关于为什么我得到一个&QUOT; System.StackOverflowException是未处理&QUOT;序列化时异常?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆