为什么这个反序列化会抛出StackOverflow异常?

时间:2012-05-04 01:04:31

标签: c# xml xml-serialization xmlserializer ixmlserializable

当我尝试反序列化时,我的FooContainer(List)会引发错误。请看这段代码的最后一部分。

public interface IFoo
{
    object Value { get; }
}

public abstract class Foo<T> : IFoo
{
    [XmlElement("Value")]
    public T Value { get; set; }
    [XmlIgnore]
    object IFoo.Value { get { return Value; } }
}

public class FooA : Foo<string> { }
public class FooB : Foo<int> { }
public class FooC : Foo<List<Double>> { }

[XmlRoot("Foos")]
public class FooContainer : List<IFoo>, IXmlSerializable
{
    public XmlSchema GetSchema()
    {
        throw new NotImplementedException();
    }

    public void ReadXml(XmlReader reader)
    {
        XmlSerializer serial = new XmlSerializer(typeof(FooContainer));
        serial.Deserialize(reader);
    }

    public void WriteXml(XmlWriter writer)
    {
        ForEach(x =>
            {
                XmlSerializer serial = new XmlSerializer(x.GetType(),
            new Type[] { typeof(FooA), typeof(FooB), typeof(FooC) });
                serial.Serialize(writer, x);
            });
    }
}

class Program
{
    static void Main(string[] args)
    {
        FooContainer fooList = new FooContainer()
        {
            new FooA() { Value = "String" },
            new FooB() { Value = 2 },
            new FooC() { Value = new List<double>() {2, 3.4 } } 
        };

        XmlSerializer serializer = new XmlSerializer(fooList.GetType(),
            new Type[] { typeof(FooA), typeof(FooB), typeof(FooC) });
        System.IO.TextWriter textWriter = new System.IO.StreamWriter(@"C:\temp\movie.xml");
        serializer.Serialize(textWriter, fooList);
        textWriter.Close();

        XmlReader reader = XmlReader.Create(@"C:\temp\movie.xml");
        var a = serializer.Deserialize(reader);
    }
}

我做错了什么?

3 个答案:

答案 0 :(得分:2)

您似乎不了解IXmlSerializable的用途。这意味着覆盖 XmlSerializer的默认行为。如果您只是启动另一个XmlSerializer来实际序列化/反序列化您的WriteXml / ReadXml方法,那么是的,您将获得StackOverflowException,因为该序列化程序将调用与完全相同的对象完全相同的WriteXml / ReadXml /方法。

只是摆脱IXmlSerializable实现,因为它实际上没有做任何事情。或者阅读这篇CP文章:

How to Implement IXmlSerializable Correctly

基本上,您应该使用Read*Write*上的标准XmlReaderXmlWriter方法来读取或写入对象。

XmlSerializerReadXml方法中使用WriteXml并不一定始终错误 - 只要您使用它来序列化/反序列化一个不同的对象,它既不等于也不包含对象图中声明类型的实例。

答案 1 :(得分:2)

我有完全相同的问题:

对我而言,您的界面set或课程IFoo中似乎缺少Foo。如果没有set,则对象变为只读,并且在尝试将XML反序列化为Object时将收到StackOverflowException

我只是将set添加到我的属性中,然后事情就解决了。

答案 2 :(得分:0)

我调试它以确保,但我的猜测是ReadXml的实现是递归的。 ReadXml调用Deserialize,调用ReadXml,调用Deserialize等。

ReadXml应该使用传入的读取器读取xml并根据Xml数据保存对象(即this)。

来自MSDN

  

ReadXml方法必须使用该信息重新构建对象   这是由WriteXml方法编写的。

     

调用此方法时,阅读器位于开头   包装您的类型信息的元素。就是这样   在开始标记之前,表示序列化的开始   宾语。当此方法返回时,它必须已读取整个元素   从头到尾,包括其所有内容。不像   WriteXml方法,框架不处理包装元素   自动。您的实施必须这样做。没有观察   这些定位规则可能导致代码生成意外的运行时   异常或损坏的数据。

     

实施此方法时,您应该考虑这种可能性   恶意用户可能会提供格式正确但无效的XML   表示以禁用或以其他方式改变行为   你的申请。