16

How can I do this? Or will the serializer automatically go with recursion, and serialize all those child objects into XML?

Give me an example how would you serialize classes that contain other classes' objects in themselves! That was the core of this question!

I've tried this, and it didn't output anything (except the XML header) to the targeted XML file.

My problem is that I need to serialize a simple class, that just holds a List object. But, those Entities also hod List objects. (Another plus would be if I could avoid the serialization of some components, because some are derived and have dictionaries in them).

public void SaveCurrent(string MapFileName)
{
    string MapPath = world_.game_.Content.RootDirectory + "/Maps/" + MapFileName + ".xml";
    StreamWriter MapWriter = new StreamWriter(MapPath);

    Map SavedMap = new Map();
    SavedMap.Entities = world_.Entities;
    XmlSerializer xSerializer = new XmlSerializer(SavedMap.GetType());

    xSerializer.Serialize(MapWriter, SavedMap);
    MapWriter.Close();
}

That's the piece of code that does the serialization.

public class Map
{
    internal string MapName;
    internal string MapDescription;
    internal string MapAuthor;
    public List<Entity> Entities = new List<Entity>();
}

And this is the class that's serialized. Could internals be counted as publics, if the serialization is called from the same assembly? The code throws exception at the SavedMap.GetType() function, and I've tried typeof(Map) too, but without success. I guess it's because I need some other way to handle each new class (deep serialization) how do I do that?

Also, I've found on some examples, that there are no interface inheritance or attributes, therefore I didn't add those either, but I'm planning to use IXmlSerializable, though I don't know how to call another serialization inside WriteXML implementation.

6
  • Can you share a sample of what you have tried? Commented Jan 30, 2010 at 23:48
  • I'm sorry I didn't do that earlier.
    – Johnny
    Commented Jan 31, 2010 at 0:06
  • "Could internals be counted as publics, if the serialization is called from the same assembly?" No. The XmlSerializer considers only public members. (In fact XmlSerializer creates a dynamic assembly to hold the code that does the serialising and deserialising, so the actual serialisation always takes place in a different assembly from your code.)
    – itowlson
    Commented Jan 31, 2010 at 0:08
  • Thanks for the tip. I've changed List to public, but now I get "There was an error reflecting type" exception. Now the error is with Entity class itself?
    – Johnny
    Commented Jan 31, 2010 at 0:22
  • (re edit 08:26Z) You say it throws; but what is the exact inner-most exception? I'm guessing it doesn't recognise the type, in which case see [XmlInclude], as already mentioned by Josh. Commented Jan 31, 2010 at 8:50

4 Answers 4

7

Add Serializable and XmlInclude your class:

[System.Serializable]
[System.Xml.Serialization.XmlInclude(typeof(Entity))]
public class Map
{
    internal string MapName;
    internal string MapDescription;
    internal string MapAuthor;
    public List<Entity> Entities = new List<Entity>();
}

Usage:

System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(Map));
serializer.Serialize(mapWriter, savedMap);
1
  • 1
    Nice answer! [System.Serializable] [System.Xml.Serialization.XmlInclude(typeof(Entity))] You don't actually need it with XmlSerializer. p.s. Also keep in mind what "List<Entity> Entities" should be List, not IList. Commented Dec 7, 2013 at 14:45
3

It will serialize the entire object graph (the object and any objects it exposes through public members, recursively) as long as all objects in the graph are serializable. Different serializers have different rules for what is serializable. For example the XmlSerializer needs a default public constructor.

Also, the XML serializer needs to be able to tell what kind of types it will serialize based only on the type info and attributes on those types. So say for example you have a class that has a property of type Animal, yet at runtime XmlSerializer finds an object of type Dog in there. To support this you will need to use the XmlInclude attribute to let it know ahead of time that it needs to support Dog.

In order to keep parts of the object graph out of the serialized output, you would use the XmlIgnore attribute. Different serializers also have different attributes for including/ignoring, etc.

Hope this helps clarify a little bit. You may also want to read up on this topic in MSDN.

2
  • Could I add [XmlIgnore] at class implementation? Because of polymorphism in a List<Component> I can't ignore InputComponent objects!
    – Johnny
    Commented Jan 31, 2010 at 0:27
  • No, the AttributeTargets only allows you to specify XmlIgnore on Field, Property, Parameter, or ReturnValue although I'm not sure how it would even be used with the last two.
    – Josh
    Commented Dec 6, 2010 at 23:58
2

About the type problem that Josh Einstein mentionned, you do not have to work with the XmlInclude attribute : you can also pass the list of types to the serializer (signature being XmlSerializer(Type baseType, Type[] extraTypes)). This should be done especially if there's a chance that the extra types list grow over time.

Finding the extra-types can be either done through reflection over the object to be serialized or reflection at startup on the loaded assemblies to fetch any needed types.

EDIT : raw example :

public abstract class Animal
{
}

public class Dog : Animal
{
}

public class Cat : Animal
{
}

public static class AnimalSerializer
{
    public static void Serialize(List<Animal> animals, Stream stream)
    {
        List<Type> animalTypes = new List<Type>();
        foreach (Animal animal in animals)
        {
            Type type = animal.GetType();
            if (!animalTypes.Contains(type))
            {
                animalTypes.Add(type);
            }
        }
        XmlSerializer serializer = new XmlSerializer(typeof(List<Animal>), animalTypes.ToArray());
        serializer.Serialize(stream, animals);
    }
}
1
  • That's another thing I've noticed and wanted to ask about! Could you share an example?
    – Johnny
    Commented Feb 2, 2010 at 15:07
2

How much control do you need? You can always implement IXmlSerializable -

http://msdn.microsoft.com/en-us/library/system.xml.serialization.ixmlserializable.aspx

Not the answer you're looking for? Browse other questions tagged or ask your own question.