CodeGym /Cursos /C# SELF /Gestión de la serialización de colecciones

Gestión de la serialización de colecciones

C# SELF
Nivel 46 , Lección 4
Disponible

1. Introducción

Por mucho que nos guste pensar que las colecciones se serializan y deserializan perfectamente “out of the box”, en proyectos reales eso no siempre sucede. A veces hay que ocultar determinadas colecciones de la serialización — por ejemplo, datos internos en caché. Otras veces hay que renombrar propiedades de colecciones para que coincidan con el contrato del API. En ciertos casos es importante controlar qué elementos se guardan o se ignoran, o incluso transformar la colección de forma especial para que el JSON resultante sea comprensible y “legible” para otros servicios.

Por suerte, System.Text.Json ofrece una forma simple y transparente de controlar la serialización mediante atributos que puedes aplicar tanto a colecciones como a elementos individuales. En esta sección seguiremos desarrollando nuestro modelo de biblioteca para entender cómo funciona esto en la práctica.

2. Excluir propiedades de colecciones: [JsonIgnore]

Empezamos por lo básico. A veces en tu clase hay una colección que no se debe serializar — por ejemplo, son datos temporales, en caché o sensibles. ¿Qué hacer? ¡Pues [JsonIgnore]!

Imagina que tenemos la clase Library, en la que añadimos la propiedad List<Book> Cache, usada solo para acceso rápido:

using System.Text.Json.Serialization;

public class Library
{
    public string Name { get; set; }

    public List<Book> Books { get; set; }

    [JsonIgnore]
    public List<Book> Cache { get; set; } // ¡No se serializa!
}
// Ejemplo de uso:
var library = new Library
{
    Name = "Biblioteca principal",
    Books = new List<Book>
    {
        new Book { Title = "El valle mágico", Author = new Author { Name = "Tove Jansson", BirthYear = 1914 } }
    },
    Cache = new List<Book>
    {
        new Book { Title = "El señor de las moscas", Author = new Author { Name = "William Golding", BirthYear = 1911 } }
    }
};

string json = JsonSerializer.Serialize(library, new JsonSerializerOptions { WriteIndented = true });
Console.WriteLine(json); // ¡En el JSON no aparece la propiedad Cache!

El resultado de la serialización será algo así:

{
  "Name": "Biblioteca principal",
  "Books": [
    {
      "Title": "El valle mágico",
      "Author": {
        "Name": "Tove Jansson",
        "BirthYear": 1914
      }
    }
  ]
}

¿Ves? Nada de “cachés” en el mundo exterior. Todo lo que esté bajo [JsonIgnore] — está oculto y seguro, como la contraseña del Wi-Fi en tu cabeza.

3. Renombrar colecciones con [JsonPropertyName]

¿Te encuentras a menudo con APIs que esperan, por ejemplo, "items" en lugar de "Books"? ¿O no quieres renombrar el campo en C# (para no liarte), pero en JSON debe “sonar” distinto?

Así se hace:

using System.Text.Json.Serialization;

public class Library
{
    public string Name { get; set; }

    [JsonPropertyName("items")]
    public List<Book> Books { get; set; }

    [JsonIgnore]
    public List<Book> Cache { get; set; }
}
// Serialización:
var library = new Library { Name = "Sucursal #1", Books = new List<Book>() };
string json = JsonSerializer.Serialize(library, new JsonSerializerOptions { WriteIndented = true });
Console.WriteLine(json);

Salida:

{
  "Name": "Sucursal #1",
  "items": []
}

Fíjate que la deserialización también mapeará correctamente la propiedad items del JSON a Books en C# — la magia funciona en ambas direcciones.

4. Controlar la serialización de colecciones y sus elementos

Para esto te harán falta JsonIgnoreCondition.WhenWritingNull y/o tipos nullable.

Sucede que una colección puede ser simplemente un campo opcional. Por ejemplo, una biblioteca recién creada puede no tener aún libros. Si no quieres que en el JSON aparezca la propiedad books: null, puedes gestionarlo con las opciones:

var library = new Library { Name = "Biblioteca vacía" };
// Books no está inicializado = null

var options = new JsonSerializerOptions
{
    DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
    WriteIndented = true
};

string json = JsonSerializer.Serialize(library, options);
Console.WriteLine(json);

Resultado:

{
  "Name": "Biblioteca vacía"
}

Y si tienes una lista vacía (pero no null), el serializador emitirá "books": []. Esa diferencia es importante, porque a veces necesitas ocultar el campo si es null, pero no si es una lista vacía.

5. El atributo [JsonIgnore] en propiedades de los elementos

Los atributos de serialización también funcionan dentro de los elementos de una colección. Puedes ocultar propiedades individuales de cada objeto en la lista.

public class Book
{
    public string Title { get; set; }
    public Author Author { get; set; }

    [JsonIgnore]
    public string InternalCode { get; set; }
}

Ahora, al serializar libros desde la colección Books, la propiedad InternalCode no aparecerá en el JSON.

6. Acceder a colecciones mediante “índices” o estructuras anidadas

A veces necesitas serializar colecciones no solo como arrays, sino, por ejemplo, como “maps” (dictionary) — si cada libro tiene un identificador único. En ese caso — sin atributos complicados para los elementos, pero usando mecanismos estándar — puedes declarar una propiedad-diccionario:

public class Library
{
    [JsonPropertyName("catalog")]
    public Dictionary<string, Book> BookCatalog { get; set; }
}

Al serializar, el diccionario se convertirá en un objeto con pares clave-valor:

var library = new Library
{
    BookCatalog = new Dictionary<string, Book>
    {
        ["978-5-699-12345-6"] = new Book { Title = "Diccionario", Author = new Author { Name = "Desconocido", BirthYear = 2000 } }
    }
};

JSON:

{
  "catalog": {
    "978-5-699-12345-6": {
      "Title": "Diccionario",
      "Author": {
        "Name": "Desconocido",
        "BirthYear": 2000
      }
    }
  }
}

Esa representación es útil para APIs donde importa mantener la relación entre la clave y el objeto.

7. Errores y dificultades al gestionar la serialización de colecciones

Si intentas serializar una colección cuyos elementos no están todos correctamente inicializados (por ejemplo, la lista contiene null), por defecto System.Text.Json escribirá esos elementos como null dentro del array.

Aunque hayas establecido DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, los elementos-null dentro de un array permanecerán — la regla se aplica a las propiedades del objeto, no al contenido de las colecciones. Para evitarlo, limpia la colección previamente: RemoveAll(b => b == null).

Una confusión común en la deserialización es la discrepancia de nombres. Si olvidas poner [JsonPropertyName], la clase esperará la propiedad Books, pero tú envías JSON con items: como resultado la colección no se rellenará y quedará vacía. ¡Siempre verifica que los nombres coincidan!

8. Tabla: dónde se aplican los atributos principales

Atributo ¿Se puede aplicar a colecciones? ¿Se puede aplicar a elementos de colecciones? Ejemplos de uso
[JsonIgnore]
Ocultar la lista o un campo dentro de Book
[JsonPropertyName]
Renombrar Books → items o Title → name
[JsonInclude]
Incluir propiedades privadas en la serialización
[JsonConverter]
Asignar un converter especial para la lista

9. Esquema de serialización de colecciones con atributos


+-------------+
|   Library   |
+-------------+
  | Name           -- se serializa como "Name"
  | Books          -- [JsonPropertyName("items")], se serializa como "items": [...]
  | Cache          -- [JsonIgnore], no se serializa
  | BookCatalog    -- [JsonPropertyName("catalog")], se serializa como "catalog": {...}
El resultado JSON será algo así:
{
  "Name": "Biblioteca municipal",
  "items": [
    {
      "Title": "1984",
      "Author": {
        "Name": "George Orwell",
        "BirthYear": 1903
      }
    },
    {
      "Title": "Grandes expectativas",
      "Author": {
        "Name": "Charles Dickens",
        "BirthYear": 1812
      }
    }
  ],
  "catalog": {
    "978-1234567890": {
      "Title": "La llamada de Cthulhu",
      "Author": {
        "Name": "Howard Phillips Lovecraft",
        "BirthYear": 1890
      }
    }
  }
}

10. Valor práctico y peculiaridades en entrevistas y proyectos reales

En condiciones “de producción” siempre hay que tener en cuenta el contrato del API externo y los requisitos de serialización. Hay que saber “ocultar” colecciones internas, respetar mayúsculas/minúsculas y el estilo de nombres, e incluso cambiar dinámicamente el esquema de serialización según la versión del cliente.

Preguntas típicas en entrevistas:

  • ¿Cómo serializar solo una parte de los datos?
  • ¿Cómo hacer para que la propiedad de la colección no aparezca en el JSON?
  • ¿Cómo mapear nombres de propiedades entre C# y JSON si difieren?
  • ¿Se pueden ocultar elementos individuales dentro de una colección durante la serialización (por ejemplo, información confidencial)?

Las respuestas giran en torno al uso correcto de atributos y parámetros de serialización: [JsonIgnore], [JsonPropertyName], opciones de JsonSerializerOptions y un manejo cuidadoso del contenido de las colecciones.

2
Tarea
C# SELF, nivel 46, lección 4
Bloqueada
Renombrar la propiedad de una colección
Renombrar la propiedad de una colección
1
Cuestionario/control
Serialización de colecciones, nivel 46, lección 4
No disponible
Serialización de colecciones
Serialización de objetos anidados y jerárquicos
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION