Как сериализовать класс, содержащий объекты других классов (рекурсивная сериализация?) - PullRequest
15 голосов
/ 31 января 2010

Как я могу это сделать? Или сериализатор автоматически пойдет с рекурсией и сериализует все эти дочерние объекты в XML?

Приведите пример, как бы вы сериализовали классы, которые содержат в себе объекты других классов! Это было ядром этого вопроса!

Я пробовал это, и он не выводил что-либо (кроме заголовка XML) в целевой файл XML.

Моя проблема в том, что мне нужно сериализовать простой класс, который просто содержит объект List. Но эти сущности также содержат объекты List. (Еще одним плюсом было бы, если бы я мог избежать сериализации некоторых компонентов, потому что некоторые являются производными и содержат словари).

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

Это кусок кода, который выполняет сериализацию.

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

И этот класс сериализован. Могут ли внутренние компоненты считаться открытыми, если сериализация вызывается из той же сборки? Код вызывает исключение в функции SavedMap.GetType(), и я тоже попробовал typeof(Map), но безуспешно. Я думаю, это потому, что мне нужен какой-то другой способ обработки каждого нового класса (глубокая сериализация), как мне это сделать?

Кроме того, я обнаружил на некоторых примерах, что нет наследования интерфейса или атрибутов, поэтому я тоже не добавил их, но я планирую использовать IXmlSerializable, хотя я не знаю, как вызвать другой Сериализация внутри реализации WriteXML.

Ответы [ 4 ]

6 голосов
/ 23 мая 2013

Добавьте Serializable и XmlInclude ваш класс:

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

Использование:

System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(Map));
serializer.Serialize(mapWriter, savedMap);
3 голосов
/ 31 января 2010

Он будет сериализовать весь граф объектов (объект и любые объекты, которые он предоставляет через открытые члены, рекурсивно), пока все объекты в графе сериализуются. Разные сериализаторы имеют разные правила для того, что сериализуемо. Например, для XmlSerializer нужен открытый конструктор по умолчанию.

Кроме того, сериализатору XML необходимо знать, какие типы он будет сериализовывать, основываясь только на информации о типах и атрибутах этих типов. Например, у вас есть класс со свойством типа Animal, но во время выполнения XmlSerializer находит там объект типа Dog. Для поддержки этого вам нужно будет использовать атрибут XmlInclude , чтобы он заранее знал, что ему нужно поддерживать Dog.

Чтобы не допустить попадания частей графа объекта в сериализованный вывод, вы должны использовать атрибут XmlIgnore . Различные сериализаторы также имеют разные атрибуты для включения / игнорирования и т. Д.

Надеюсь, это поможет прояснить немного. Вы также можете прочитать эту тему в в MSDN .

2 голосов
/ 31 января 2010

Что касается проблемы типов, о которой упоминал Джош Эйнштейн, вам не нужно работать с атрибутом XmlInclude: вы также можете передать список типов в сериализатор (подпись XmlSerializer(Type baseType, Type[] extraTypes)). Это следует делать, особенно если есть вероятность, что список дополнительных типов со временем будет расти.

Поиск дополнительных типов можно выполнить либо путем отражения над сериализуемым объектом, либо путем отражения при запуске на загруженных сборках для извлечения любых необходимых типов.

РЕДАКТИРОВАТЬ: необработанный пример:

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);
    }
}
2 голосов
/ 31 января 2010

Какой контроль вам нужен?Вы всегда можете реализовать IXmlSerializable -

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

...