3

I want to serialize the following:

[Serializable]
[DefaultPropertyAttribute("Name")]
[XmlInclude(typeof(ItemInfo))]
[XmlInclude(typeof(ItemInfoA))]
[XmlInclude(typeof(ItemInfoB))] 
public class ItemInfo
{
    public string name;

    [XmlArray("Items"), XmlArrayItem(typeof(ItemInfo))]
    public ArrayList arr;

    public ItemInfo parentItemInfo;
}

[Serializable]
[XmlInclude(typeof(ItemInfo))]
[XmlInclude(typeof(ItemInfoA))]
[XmlInclude(typeof(ItemInfoB))] 
public class ItemInfoA : ItemInfo
{
...
}

[Serializable]
[XmlInclude(typeof(ItemInfo))]
[XmlInclude(typeof(ItemInfoA))]
[XmlInclude(typeof(ItemInfoB))] 
public class ItemInfoB : ItemInfo
{
...
}

The class itemInfo describes a container which can hold other itemInfo objects in the array list, the parentItemInfo describes which is the parent container of the item info.

Since ItemInfoA and ItemInfoB derive from ItemInfo they can also be a member of the array list and the parentItemInfo, therefore when trying to serialize these objects (which can hold many objects in hierarchy) it fails with exception

IvvalidOperationException.`there was an error generating the xml file `

My question is:

What attributes do I need to add the ItemInfo class so it will be serializable?

Note: the exception is only when the ItemInfo[A]/[B] are initialized with parentItemInfo or the arrayList.

Help please!

Thanks!

4
  • 1
    Private members aren't serialized with XmlSerializer, so arr is never going to be serialized in this scenario, nor is parentItemInfo. I think we need a reproducible example here... also, not important, but [Serializable] isn't used by XmlSerializer Commented Feb 1, 2011 at 7:23
  • 1
    Oh, and why use ArrayList here? are you on 1.1? Commented Feb 1, 2011 at 7:24
  • Also - none of the attributes on ItemInfoA or ItemInfoB are used here... Commented Feb 1, 2011 at 7:27
  • Marc Gravell - sorry, see my edited question Commented Feb 1, 2011 at 7:28

1 Answer 1

8

With the edited question, it looks like you have a loop. Note that XmlSerializer is a tree serializer, not a graph serializer, so it will fail. The usual fix here is to disable upwards traversal:

[XmlIgnore]
public ItemInfo parentItemInfo;

Note you will have to manually fixup the parents after deserialization, of course.

Re the exception - you need to look at the InnerException - it probably tells you exactly this, for example in your (catch ex):

while(ex != null) {
    Debug.WriteLine(ex.Message);
    ex = ex.InnerException;
}

I'm guessing it is actually:

"A circular reference was detected while serializing an object of type ItemInfoA."


More generally on the design, honestly that (public fields, ArrayList, settable lists) is bad practice; here's a more typical re-write that behaves identically:

[DefaultPropertyAttribute("Name")]
[XmlInclude(typeof(ItemInfoA))]
[XmlInclude(typeof(ItemInfoB))] 
public class ItemInfo
{
    [XmlElement("name")]
    public string Name { get; set; }

    private readonly List<ItemInfo> items = new List<ItemInfo>();
    public List<ItemInfo> Items { get { return items; } }

    [XmlIgnore]
    public ItemInfo ParentItemInfo { get; set; }
}
public class ItemInfoA : ItemInfo
{
}
public class ItemInfoB : ItemInfo
{
}

as requested, here's a general (not question-specific) illustration of recursively setting the parents in a hive (for kicks I'm using depth-first on the heap; for bredth-first just swap Stack<T> for Queue<T>; I try to avoid stack-based recursion in these scenarios):

public static void SetParentsRecursive(Item parent)
{
    List<Item> done = new List<Item>();
    Stack<Item> pending = new Stack<Item>();
    pending.Push(parent);
    while(pending.Count > 0)
    {
        parent = pending.Pop();
        foreach(var child in parent.Items)
        {
            if(!done.Contains(child))
            {
                child.Parent = parent;
                done.Add(child);
                pending.Push(child);
            }                
        }
    }
}
Sign up to request clarification or add additional context in comments.

3 Comments

How can I deserialize it as well?
@gln deserialize it as normal, but then you would have to either walk the tree and assign the parents, or write a custom list implementation that does this for you
@gln - seriously? That is a pretty simple bit of recursion... I'll add the example later (not at a PC right now), but...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.