Search code examples
c#xmlxml-serializationxmlserializerixmlserializable

Why this deserialized throws me StackOverflow exception?


When I try to deserialized my FooContainer (List) throws me an error. Please, just watch the last part of this code.

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

What am I doing wrong?


Solution

  • You don't seem to understand what IXmlSerializable is for. It's meant for overriding the default behaviour of an XmlSerializer. If you just spin up another XmlSerializer to actually serialize/deserialize in your WriteXml/ReadXml methods then yes, you will get a StackOverflowException because that serializer is going to call the exact same WriteXml/ReadXml/ method it came from on exactly the same object.

    Just get rid of that IXmlSerializable implementation, since it doesn't actually do anything. Or read this CP article:

    How to Implement IXmlSerializable Correctly

    Basically, you are supposed to use the standard Read* and Write* methods on XmlReader or XmlWriter to read or write the object.

    It's not necessarily always wrong to use an XmlSerializer inside a ReadXml or WriteXml method - as long as you're using it to serialize/deserialize a different object, one which neither equals nor contains an instance of the declaring type in the object graph.