2010-01-30 11 views
14

¿Cómo puedo hacer esto? ¿O el serializador irá automáticamente con la recursión y serializará todos esos objetos secundarios en XML?¿Cómo serializar una clase que contiene objetos de otras clases (serialización recursiva?)

Dame un ejemplo de cómo serializarías las clases que contienen los objetos de otras clases en sí mismas. Ese fue el núcleo de esta pregunta!

He intentado esto, y no produjo nada (excepto el encabezado XML) en el archivo XML de destino.

Mi problema es que necesito serializar una clase simple, que solo contiene un objeto List. Pero esas Entidades también tienen objetos List. (Otra ventaja sería si pudiera evitar la serialización de algunos componentes, porque algunos se derivan y tienen diccionarios en ellos).

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

Esa es la pieza de código que hace la serialización.

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

Y esta es la clase que se serializa. ¿Se podrían contar los elementos internos como públicos, si se llama a la serialización desde el mismo conjunto? El código arroja una excepción en la función SavedMap.GetType(), y también he intentado typeof(Map), pero sin éxito. Supongo que es porque necesito otra forma de manejar cada nueva clase (serialización profunda) ¿cómo hago eso?

Además, he encontrado en algunos ejemplos, que no hay herencia de interfaz o atributos, por lo tanto, tampoco los agregué, pero estoy pensando en usar IXmlSerializable, aunque no sé cómo llamar otra serialización dentro de la implementación de WriteXML.

+0

¿Se puede compartir una muestra de lo que has probado? –

+0

Lo siento, no lo hice antes. – Johnny

+0

"¿Se podrían contar los elementos internos como públicos, si se llama a la serialización desde el mismo ensamblaje?" No. El XmlSerializer solo considera miembros públicos. (De hecho, XmlSerializer crea un ensamblaje dinámico para contener el código que serializa y deserializa, por lo que la serialización real * siempre * tiene lugar en un ensamblaje diferente de su código). – itowlson

Respuesta

2

Sobre el problema tipo que Josh Einstein mencionado, usted no tiene que trabajar con el atributo XmlInclude: también puede pasar la lista de tipos de serializador (firma siendo XmlSerializer(Type baseType, Type[] extraTypes)) Esto debería hacerse especialmente si existe la posibilidad de que la lista de tipos extra crezca con el tiempo.

La búsqueda de los tipos adicionales se puede hacer a través de la reflexión sobre el objeto que se serializará o la reflexión al inicio en los ensamblajes cargados para obtener los tipos necesarios.

EDIT: prima ejemplo:

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); 
    } 
} 
+0

¡Esa es otra cosa que he notado y sobre la que quería preguntar! ¿Podría compartir un ejemplo? – Johnny

+0

¡Justo lo que necesitaba! ¡Gracias! – Johnny

3

serializará todo el gráfico de objeto (el objeto y cualquier objeto que expone a través de miembros públicos, de forma recursiva), siempre y cuando todos los objetos en el gráfico sean serializables. Los diferentes serializadores tienen reglas diferentes para lo que es serializable. Por ejemplo, el XmlSerializer necesita un constructor público predeterminado.

Además, el serializador XML necesita poder decir qué tipo de tipos se serializarán basándose únicamente en la información de tipo y los atributos de esos tipos. Por ejemplo, supongamos que tiene una clase que tiene una propiedad de tipo Animal, pero en tiempo de ejecución, XmlSerializer encuentra un objeto de tipo Dog allí. Para respaldar esto, necesitará usar el atributo XmlInclude para avisarle por adelantado que necesita admitir a Dog.

Para mantener partes del gráfico objeto fuera de la salida serializada, usaría el atributo XmlIgnore. Los diferentes serializadores también tienen diferentes atributos para incluir/ignorar, etc.

Espero que esto ayude a aclarar un poco. También puede leer en this topic in MSDN.

+0

¿Podría agregar [XmlIgnore] en la implementación de la clase? Debido al polimorfismo en una lista , no puedo ignorar los objetos InputComponent. – Johnny

+0

No, AttributeTargets solo le permite especificar XmlIgnore en Field, Property, Parameter o ReturnValue, aunque no estoy seguro de cómo se usaría con los dos últimos. – Josh

6

Añadir Serializable y XmlInclude su clase:

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

Uso:

System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(Map)); 
serializer.Serialize(mapWriter, savedMap); 
+1

¡Buena respuesta! '[System.Serializable] [System.Xml.Serialization.XmlInclude (typeof (Entity))]' En realidad, no lo necesita con XmlSerializer. p.s. También tenga en cuenta que "Lista Entidades" debe ser Lista, no IList. – Alexanderius

Cuestiones relacionadas