🎃 Grandes descuentos en libros en línea, eformaciones y vídeos*. Código CALABAZA30. Pulse aquí
¡Acceso ilimitado 24/7 a todos nuestros libros y vídeos! Descubra la Biblioteca Online ENI. Pulse aquí
  1. Libros
  2. C# 10 y Visual Studio Code
  3. Serialización
Extrait - C# 10 y Visual Studio Code Fundamentos del lenguaje
Extractos del libro
C# 10 y Visual Studio Code Fundamentos del lenguaje
1 opinión
Volver a la página de compra del libro

Serialización

Serialización en C#

Hoy en día, el lenguaje C# es uno de los más usados para desarrollar aplicaciones web. Uno de los problemas más frecuentes durante la comunicación en programación web es conseguir transferir objetos hacia y desde una aplicación. Para eso, el objeto se debe transformar en un formato universal. Esta transformación se llama serialización. Este proceso permite recuperar el objeto representado bajo un formato intercambiable; con frecuencia este formato tiene una forma textual.

Para que los datos puedan transitar, hay que usar un flujo de datos (llamado stream en inglés, de ahí el nombre de la clase base en C#: Stream). Estos flujos pueden tomar varias formas, como por ejemplo un flujo de datos en memoria (representado por la clase MemoryStream en C#) o incluso un flujo de datos hacia un archivo en el disco (representado por la clase FileStream en C#).

Hay varias maneras de serializar un objeto; estas son algunas de ellas:

  • La serialización binaria, que permite representar un objeto en un formato binario. 

  • La serialización XML, que transforma el objeto en cadena de caracteres al formato XML.

  • La serialización JSON, que transforma el objeto en cadena de caracteres al formato JSON.

En este capítulo vamos a abordar tres modos de serialización para transformar un objeto a un formato dado, pero también para poder recuperar un objeto desde...

Serialización binaria

El enfoque binario es el modo de serialización más simple para implantar. También es el que permite almacenar mayor cantidad de información en el tipo del objeto y tiene más fiabilidad de conversión de los valores y tipos almacenados. Sin embargo, su formato es propietario: no es portable ni compatible con otros lenguajes y soluciones, de manera que solo lo usaremos si el emisor y el destinatario son programas en C#.

Con la llegada de .NET 6 y C# 10, no se recomienda en absoluto usar este modo de serialización. Las explicaciones y el funcionamiento descritos en esta sección solo se proponen con fines de seguimiento, para los lectores que necesiten hacer el mantenimiento de un sistema usando este sistema de serialización. No se recomienda usar los objetos vistos en esta sección para aplicaciones nuevas porque están marcados como obsoletos en .NET 6 y se eliminarán en .NET 7.

Dos planteamientos permiten activar la serialización binaria:

  • Usando los atributos apropiados en un tipo dado.

  • Implementando la interfaz ISerializable.

Los atributos son más fáciles y rápidos de implantar, pero menos flexibles que la implementación de la interfaz ISerializable. Es recomendable elegir la mejor solución en función del objetivo.

1. Uso de los atributos

Este planteamiento es el más sencillo y rápido de implantar. Considerando la siguiente clase, solo hay que añadir el atributo [Serializable] encima de la declaración de la clase:

[Serializable] 
public class Persona 
{ 
    public string Nombre { get; set; } 
    public string Apellido { get; set; } 
} 

De este modo, cuando se pida serializar una variable de tipo Persona, se informará al serializador, mediante la presencia del atributo, de que debe considerar la serialización de cada dato contenido en el interior del tipo, en forma de campos. Cada uno de los datos debe ser serializable; en caso contrario, se devolverá una excepción durante el proceso.

Una vez marcado el objeto, se puede usar el serializador binario, BinaryFormatter, que se encuentra en el espacio de nombres System.Runtime.Serialization.Formatters.Binary, para serializar el objeto en un stream de datos. El stream se puede guardar...

Serialización XML

A diferencia del enfoque binario, la serialización en XML se basa en un formato reconocido como un estándar en el sector. Usado durante mucho tiempo, el XML es un lenguaje de señalización bastante prolífico, pero de hecho también bastante potente y ampliable. En la actualidad todavía se usa, especialmente en el enfoque de archivos de configuración o incluso de mensajes de intercambios para los servicios que usan el protocolo SOAP.

.NET ofrece dos maneras de gestionar la serialización, que vamos a tratar en esta sección. Vamos a empezar por el enfoque de bajo nivel, más eficiente, pero también con más limitaciones.

1. XmlSerializer

La clase XmlSerializer, que se encuentra en el espacio de nombres System.Xml.Serialization, permite realizar la deserialización de objetos en XML. El funcionamiento se parece al del BinaryFormatter, es decir, que hay que proporcionar un objeto y un stream. La única diferencia notable entre los dos es que es necesario especificar el tipo que se ha de gestionar durante la creación de la instancia de la clase XmlSerializer, usando la palabra clave typeof:

var p = new PersonaXml { Nombre = " Christophe", Apellido = "Mommer" }; 
  
var serializer = new XmlSerializer(typeof(PersonaXml)); 
 
using (var stream = new FileStream("person.xml", FileMode.Create)) 
{ 
    serializer.Serialize(stream, p); 
} 
using (var stream = new FileStream("person.xml", FileMode.Open)) 
{ 
    var p2 = (PersonaXml)serializer.Deserialize(stream); 
    System.Console.WriteLine("Hola " + p2.Nombre + " " + p2.Apellido); 
} 

La serialización con este enfoque se basa en el uso de atributos que permiten decir lo que se quiere serializar o no, y cómo debe hacerse la serialización.

Como recordatorio, el formato XML se basa en elementos que pueden tener un contenido, pero también atributos. Se puede personalizar la salida con los atributos [XmlElement] y [XmlAttribute]. Estos últimos pueden tomar como parámetro el nombre que se quiere usar para el elemento o el atributo:

[Serializable] 
public class PersonaXml 
{  
    [XmlElement("Name")] 
    public string Nombre { get; set; } 
    public string Apellido { get; set; }  
    [XmlAttribute] 
    public int Edad { get; set; } 
} 

La clase modificada aquí arriba da el siguiente XML en la serialización:

<?xml version="1.0"?> 
<PersonaXml xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema" Edad="33">  
  <Name>Christophe</Name> 
  <Apellido>Mommer</Apellido> 
</PersonaXml> 

Se puede observar que la edad se ha colocado como atributo en el elemento principal, y el nombre se ha puesto dentro de un elemento llamado "Name".

El orden de salida de los elementos también es controlable especificando el valor Order en el atributo XmlElement:

[Serializable] 
public class PersonaXml 
{ 
    [XmlElement("Name")] ...

Serialización JSON

En la actualidad, el formato de datos JSON es el más usado para intercambiar información debido a su simplicidad, pero también a su ligereza sintáctica respecto al XML. Por ello, el framework .NET permite tratar el formato JSON de manera nativa.

Desde el framework .NET Core 3, los ingenieros de Microsoft han añadido directamente en el framework una manera nueva de tratar los flujos JSON, más eficiente que el planteamiento anterior, y todo esto para dejar de depender del paquete comunitario más ampliamente usado hasta entonces: NewtonSoft.Json.

A semejanza de la API proporcionada para el tratamiento XML, hay dos enfoques para tratar el JSON:

  • De manera procesal, leyendo el flujo de extremo a extremo con ayuda de un cursor gracias a las clases Utf8JsonReader y Utf8JsonWriter.

  • Con un enfoque orientado al documento, a semejanza de XDocument, gracias a la clase JsonDocument.

1. Utf8JsonReader y Utf8JsonWriter

El formato JSON es relativamente sencillo porque el tipo de datos encontrado durante la lectura de un flujo JSON forzosamente está contenido en la lista siguiente:

  • Inicio o final del objeto.

  • Inicio o final de la tabla.

  • Nombre de propiedad.

  • Valor (cadena de caracteres, numérica o booleana).

Por ello, el enfoque sostenido en la clase Utf8JsonReader se centra en la lectura de los datos uno por uno, y es función del desarrollador definir lo que quiere realizar.

Consideramos el siguiente flujo JSON:

var json = @"{ 
  ""Nombre"" : ""Christophe"", 
  ""Apellido"" : ""Mommer"", 
  ""Edad"" : 33, 
  ""Dirección"" : { 
    ""Calle"": ""Plaza del Reloj"", 
    ""Ciudad"" : ""Talavera de la Reina"" 
  } 
}"; 

Cuando se utiliza el carácter @ delante de una cadena de caracteres, se debe huir del uso de comillas en la cadena. Considerando que no se puede utilizar la barra invertida, es necesario usar comillas dobles.

Se puede usar la clase Utf8JsonReader para leer el flujo de manera procesal. Para poder usar esta clase, hay que construirla con una tabla de bytes que contiene...

Ejercicio

El propósito de este ejercicio es poner en práctica las distintas formas de serialización vistas en este libro, tanto de lectura como de escritura.

1. Enunciado

La base de trabajo es el proyecto desarrollado en el capítulo Programación orientada a objetos y en el capítulo Algoritmia: el juego para adivinar el número misterioso. Aquí, se trata de crear una tabla de puntuaciones que se mostrará debajo del menú del juego, proponiéndole al jugador introducir su nombre si se clasifica como uno de los cinco mejores jugadores.

Para hacerlo, se calcula una cantidad de puntos correspondiente a la siguiente fórmula: número de posibilidades + (número de intentos que quedan elevado a la dificultad).

Por ejemplo, si un jugador ha intentado adivinar un número entre 1 y 100, hay 100 posibilidades. Si ha elegido jugar en modo fácil, el nivel de dificultad es 1. Entonces hay que poner la cantidad de intentos que quedan como potencia de este número. Si el jugador ha ganado en cuatro intentos, le quedan 6, lo que da 100 + 6 elevado a 1 = 106 puntos.

El operador C# que se usará para hacer una potencia es ^. Así, para almacenar en una variable 2 elevado a 3, se escribe var i = 2 ^ 3;.

Entonces hay que leer la tabla de las puntuaciones y ver si el jugador puede entrar en el grupo de los cinco mejores. En caso afirmativo, se le pide que introduzca su nombre para registrarlo en la posición correcta.

No hay limitaciones específicas sobre el tipo de serialización...