Как сериализовать класс, содержащий объекты других классов (рекурсивная сериализация?)
Как я могу это сделать? Или сериализатор автоматически перейдет с рекурсией и сериализует все эти дочерние объекты в 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.
Ответы
Ответ 1
О проблеме типа, которую упоминал Джош Эйнштейн, вам не нужно работать с атрибутом XmlInclude: вы также можете передать список типов в сериализатор (подпись XmlSerializer(Type baseType, Type[] extraTypes)
). Это должно быть сделано, особенно если есть вероятность того, что список дополнительных типов будет расти со временем.
Поиск дополнительных типов может быть осуществлен путем отражения объекта, подлежащего сериализации или отражения при запуске на загруженных сборках, для извлечения любых необходимых типов.
EDIT: исходный пример:
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
Добавить 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
Он сериализует весь граф объекта (объект и любые объекты, которые он предоставляет через публичные элементы, рекурсивно), если все объекты в графе сериализуемы. Различные сериализаторы имеют разные правила для сериализуемых. Например, XmlSerializer нуждается в общедоступном конструкторе по умолчанию.
Кроме того, сериализатор XML должен быть способен определить, какие типы он будет сериализован, основываясь только на информации типа и атрибутах этих типов. Так скажем, например, у вас есть класс, который имеет свойство типа Animal, но во время выполнения XmlSerializer находит объект типа Dog в нем. Чтобы поддержать это, вам нужно будет использовать атрибут XmlInclude, чтобы заранее знать его, чтобы он поддерживал Dog.
Чтобы сохранить части графического объекта из сериализованного вывода, вы должны использовать атрибут XmlIgnore. Различные сериализаторы также имеют разные атрибуты для включения/игнорирования и т.д.
Надеюсь, что это поможет прояснить немного. Вы также можете прочитать этот раздел в MSDN.
Ответ 4
Сколько контроля вам нужно? Вы всегда можете реализовать IXmlSerializable -
http://msdn.microsoft.com/en-us/library/system.xml.serialization.ixmlserializable.aspx