jueves, 20 de mayo de 2010

Serialización de clases derivadas

Al referirme a clases derivadas me refiero a clases que heredan ya sea de interfaces, clases abstractas o clases concretas, al serializar este tipo de clases muy amplias utilizando la herencia es un poco complejo el estar "marcando" por clase que es un atributo o que es una clase raíz y cosas así para después su serialización, entonces existe una forma que nos permite hacer este trabajo muy cómodamente y sin tener que estar marcando cada clase con atributos y demás. Esta forma consiste en personalizar la serializacion de objetos, utilizando:

XmlAttributes

XmlElementAttribute

XmlAttributeOverrides

XmlSerializer

Supongamos que tenemos esta jerarquia de clases:

public class Name
{


public Name() { }


public Name(string Name, string _1erApellido, string _2doApellido)
{
nombre = Name;

primerApellido = _1erApellido;

segundoApellido = _2doApellido;

}

public stringnombre { set;get;}

public string primerApellido {


set; get; }


public
string segundoApellido { set; get; }


public
override
string ToString()

{


return nombre + " " + primerApellido + " " + segundoApellido;

}

}

public class Persona {


public Persona() { }


public Persona(Name Nombre, string fechaNacimiento)

{


this.Nombre = Nombre;


this.FechaNacimiento = fechaNacimiento;

}


public
Name Nombre { get; set; }


public
string FechaNacimiento { get; set; }

}

public
class
PersonaFisica:Persona

{


public
string RazonSocial { set; get; }


public
string homoClave { set; get; }


public PersonaFisica() { }


public PersonaFisica(Name _nombre, string _fechaNacimiento, string homoclave)

: base(_nombre, _fechaNacimiento)

{


this.homoClave = homoclave; this.RazonSocial = Nombre.ToString();


 

}

}

public class Interprete

{


public
string Nombre { set; get; }

}

public
class
Disco

{


public Disco() { }


public
string Titulo { set; get; }


public
Interprete Interprete { set; get; }


public
string Clasificacion { set; get; }


public
string TipoDisco { set; get; }

}

[XmlRootAttribute("prestamo")]
public class Prestamo{



public Prestamo(){}


public Prestamo(PersonaFisica Cliente,Disco Articulo)

{

DatosCliente = Cliente;

ArticuloAPrestar = Articulo;

fechaInicio = DateTime.Now.ToString(); ;

}


public
PersonaFisica DatosCliente { set; get; }


public
Disco ArticuloAPrestar { set; get; }


public
string fechaInicio { set; get; }

}

Ahora bien, como se puede dar uno cuenta,estas clases estan bastantes creciditas,donde una implementa a todas,la serializacion se vuelve un tanto ruda porque se estan utilizando clases sobre clases y asi sucesivamente, ahora bien para serializar todas estas a la vez,nos ayudamos de nuestros amigos mencionados anteriormente, primero, necesitamos instanciar Un objeto XmlAttributes y un XmlElementAttribute:

XmlAttributes atribXml = new
XmlAttributes();

XmlElementAttribute elemntAtrib = new
XmlElementAttribute();

A la propiedad Type de "elemntAtrib"(XmlElementAttribute) se le asigna el tipo de dato que queremos serizalizar, en este caso seria de tipo Prestamo.

elemntAtrib.Type = typeof(Prestamo);

Despues al objeto" atribXml " de tipo XmlAttributes le agregamos un elemento XmlElementAttribute:

atribXml.XmlElements.Add(elemntAtrib);

Ahora bien, despues de esto vamos a necesitar reemplazar el modo predeterminado de serializar los objetos, y esto lo hacemos instanciando un objeto de tipo "XmlAttributeOverrides",que es lo que necesitamos para nuestros fines.

XmlAttributeOverrides atribSobreEscrito = new
XmlAttributeOverrides();

Mediante el metodo Add agregamos un objeto XmlAttributes.

atribSobreEscrito.Add(typeof(List<Prestamo>), atribXml);

NOTA: al agregar un XmlAttributes necesitamos especificar el tipo de dato del cual queremos serializar, en este caso es una lista generica que guarda objetos de tipo Prestamo,seguido del objeto XmlAttributes que hemos creado.

Ahora bien, ya que tenemos todas las piezas del puzzle solo tenemos que llamar a la clase magica que hace el trabajo y para eso instanciamos un objetito de esta:

XmlSerializer serializer = new
XmlSerializer(typeof(List<Prestamo>), atribSobreEscrito);

Y por ultimo vamos a escribir sobre el archivo.


 

TextWriter writer = new
StreamWriter(@"C:\\Prestamos.xml");

Y serializar:

serializer.Serialize(writer, Prestamos);

writer.Close();

codigo Serializar:

XmlAttributes atribXml = new XmlAttributes();
XmlElementAttribute elemntAtrib = new
XmlElementAttribute();

elemntAtrib.Type = typeof(Prestamo);

atribXml.XmlElements.Add(elemntAtrib);


XmlAttributeOverrides atribSobreEscrito = new
XmlAttributeOverrides();

atribSobreEscrito.Add(typeof(List<Prestamo>), atribXml);


XmlSerializer serializer =new
XmlSerializer(typeof(List<Prestamo>), atribSobreEscrito);


TextWriter writer = new
StreamWriter(@"C:\\Prestamos.xml");

serializer.Serialize(writer, Prestamos);

writer.Close();

Por ultimo para deserializar el objeto es similar:

Codigo Deserializar:

     ///, se instancia un objeto XmlAttributeOverrides, XmlAttributes, XmlElementAttribute

XmlAttributeOverrides atribSobreEscrito = new
XmlAttributeOverrides();


XmlAttributes atribXml = new
XmlAttributes();


XmlElementAttribute elemntAtrib = new
XmlElementAttribute();

elemntAtrib.Type = typeof(Prestamo);

atribXml.XmlElements.Add(elemntAtrib);

atribSobreEscrito.Add(typeof(List<Prestamo>), atribXml);


XmlSerializer serializer = new
XmlSerializer(typeof(List<Prestamo>), atribSobreEscrito);


FileStream fsFile = new
FileStream(path, FileMode.Open);//se abre el archivo en el path especificado para leerlo

Prestamos = (List<Prestamo>) serializer.Deserialize(fsFile);//Prestamos es una lista de prestamos(List<Prestamo>)), a esta se le asignan los elementos que se deserealizan del archivo.

Y bueno espero que se entienda la explicacion a grandes rasgos.

Saludos.

4 comentarios:

  1. copie tu codigo pero me sale un error donde dice que en el main en la ultima line de serializacion "Prestamos" no existe en el contexto actual. Solo es para fines de aprendisaje dado que soy novato en esto

    ResponderEliminar
  2. y al compilar sale este error Error al reflejar el tipo 'System.Collections.Generic.List`1[ConsoleApplication14.Prestamo]

    ResponderEliminar
    Respuestas
    1. mm pues de hecho estaría bien que describieras los pasos que hiciste para llegar al error,desde los minimos detalles, si borraste el archivo fisico, que tipo de datos escribiste etc, volví a ejecutarlo un par de veces y no me marca ningun error. ejecute la aplicacion con VS 2010.
      Saludos

      Eliminar
  3. Este comentario ha sido eliminado por el autor.

    ResponderEliminar

CoMeNtArIoS y MaS...