1

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?

Darf Zon
  • 6,268
  • 20
  • 90
  • 149

3 Answers3

3

I had the exact same Problem:

To me it seems that you are missing set in your interface IFoo or class Foo. Without set the object becomes readonly and you will receive a StackOverflowException when trying to deserialize XML to Object.

I simply added set to my attributes, and the thing solved itself.

jonsca
  • 10,218
  • 26
  • 54
  • 62
  • Right: The deserializer uses the setter as well. Make sure you have a public constructor (without Parameters) as well. – Max Sep 27 '12 at 12:32
2

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.

Aaronaught
  • 120,909
  • 25
  • 266
  • 342
  • Thanks for your answer, I got what I should do now. My doubt until now is how can I store the property Value if is T dataType? XmlSerialization write each type of datatype, I really have no idea about how to write this value using XmlWriter. – Darf Zon May 04 '12 at 03:04
  • @DarfZon: Generics and XML don't mix particularly well. In your specific yet abstract example, the only way you could be sure that `Foo` is actually serializable is to place a constraint on `T` which you know is serializable. Right now it doesn't look like `Foo` even does much of anything; maybe if you explained more about what your real problem is (in a new question) some people might be able to help get you straightened out. – Aaronaught May 04 '12 at 04:11
0

I'd debug it to make sure, but my guess is your implementation of ReadXml is recursive. ReadXml calls Deserialize, which calls ReadXml, which calls Deserialize, etc.

ReadXml should read the xml using the reader that's passed in and hydrate the object (i.e. this) based on the Xml data.

from MSDN

The ReadXml method must reconstitute your object using the information that was written by the WriteXml method.

When this method is called, the reader is positioned at the start of the element that wraps the information for your type. That is, just before the start tag that indicates the beginning of a serialized object. When this method returns, it must have read the entire element from beginning to end, including all of its contents. Unlike the WriteXml method, the framework does not handle the wrapper element automatically. Your implementation must do so. Failing to observe these positioning rules may cause code to generate unexpected runtime exceptions or corrupt data.

When implementing this method, you should consider the possibility that a malicious user might provide a well-formed but invalid XML representation in order to disable or otherwise alter the behavior of your application.

D Stanley
  • 149,601
  • 11
  • 178
  • 240