CodeGym /Cursos /C# SELF /Controle de serialização de coleções

Controle de serialização de coleções

C# SELF
Nível 46 , Lição 4
Disponível

1. Introdução

Por mais que a gente queira acreditar que coleções se serializam e desserializam perfeitamente “out of the box”, em projetos reais nem sempre é assim. Às vezes é preciso esconder certas coleções da serialização — por exemplo, dados de cache internos. Às vezes é necessário renomear propriedades de coleções para atender ao contrato da API. Em alguns casos é importante controlar quais elementos são preservados ou ignorados, ou até transformar a coleção de um jeito que o JSON final fique legível e “amigável” para outros serviços.

Felizmente, o System.Text.Json oferece uma forma simples e transparente de controlar a serialização usando atributos que podem ser aplicados tanto a coleções quanto a elementos individuais. Nesta seção vamos evoluir nosso modelo de biblioteca para entender como isso funciona na prática.

2. Excluir propriedades de coleção: [JsonIgnore]

Começamos pelo básico. Às vezes sua classe tem uma coleção que não deve ser serializada — por exemplo, dados temporários, cache ou informações sensíveis. O que fazer? Claro: [JsonIgnore]!

Suponha que temos a classe Library com a propriedade List<Book> Cache, usada só para acesso 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; } // Não é serializado!
}
// Exemplo de uso:
var library = new Library
{
    Name = "Biblioteca Principal",
    Books = new List<Book>
    {
        new Book { Title = "Vale Encantado", Author = new Author { Name = "Tove Jansson", BirthYear = 1914 } }
    },
    Cache = new List<Book>
    {
        new Book { Title = "O Senhor das Moscas", Author = new Author { Name = "William Golding", BirthYear = 1911 } }
    }
};

string json = JsonSerializer.Serialize(library, new JsonSerializerOptions { WriteIndented = true });
Console.WriteLine(json); // No JSON não existe a propriedade Cache!

O resultado da serialização ficará mais ou menos assim:

{
  "Name": "Biblioteca Principal",
  "Books": [
    {
      "Title": "Vale Encantado",
      "Author": {
        "Name": "Tove Jansson",
        "BirthYear": 1914
      }
    }
  ]
}

Viu? Nada de “caches” no mundo externo. Tudo que está sob [JsonIgnore] — fica escondido e seguro, como a senha do Wi-Fi na sua cabeça.

3. Renomear coleções com [JsonPropertyName]

Com frequência você encontra APIs que esperam, por exemplo, "items" em vez de "Books". Ou você não quer renomear o campo em C# (pra não se confundir), mas no JSON ele precisa “soar” diferente.

Aqui está como fazer:

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; }
}
// Serialização:
var library = new Library { Name = "Filial #1", Books = new List<Book>() };
string json = JsonSerializer.Serialize(library, new JsonSerializerOptions { WriteIndented = true });
Console.WriteLine(json);

Saída:

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

Repare que a desserialização também vai mapear corretamente items do JSON para Books no C# — a mágica funciona nos dois sentidos.

4. Controlando a serialização de coleções e seus elementos

Para isso você vai usar JsonIgnoreCondition.WhenWritingNull e/ou tipos nullable.

Pode acontecer de uma coleção ser um campo opcional. Por exemplo, uma biblioteca criada agora pode ainda não ter livros. Se você não quer que apareça no JSON a propriedade books: null, dá pra controlar isso com opções:

var library = new Library { Name = "Biblioteca Vazia" };
// Books não inicializado = null

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

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

Resultado:

{
  "Name": "Biblioteca Vazia"
}

Se você tiver uma lista vazia (mas não null), o serializador vai emitir "books": []. Essa diferença é importante: às vezes você quer ocultar o campo quando ele é null, mas não quando é uma lista vazia.

5. O atributo [JsonIgnore] em propriedades de elementos

Atributos de serialização também funcionam dentro dos elementos da coleção. Dá pra esconder propriedades individuais de cada objeto na lista.

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

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

Agora, ao serializar um Book dentro de Books, a propriedade InternalCode não vai aparecer no JSON.

6. Endereçamento de coleções via “índices” ou estruturas aninhadas

Às vezes precisamos serializar coleções não apenas como arrays, mas como “maps” (dictionary) — por exemplo, quando cada livro tem um identificador único. Nesse caso — sem atributos mirabolantes para elementos, mas usando recursos padrão — você declara uma propriedade de dicionário:

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

Ao serializar, o dicionário vira um objeto com pares chave-valor:

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

JSON:

{
  "catalog": {
    "978-5-699-12345-6": {
      "Title": "Dicionário",
      "Author": {
        "Name": "Desconhecido",
        "BirthYear": 2000
      }
    }
  }
}

Essa representação é conveniente para APIs onde é importante manter a associação entre chave e objeto.

7. Erros e dificuldades ao gerenciar a serialização de coleções

Se você tentar serializar uma coleção que tem elementos não inicializados (por exemplo, na lista existem null), por padrão o System.Text.Json vai escrever esses elementos como null no array.

Mesmo que você tenha definido DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, elementos-null dentro do array vão permanecer — essa regra se aplica a propriedades do objeto, não ao conteúdo das coleções. Para evitar isso, limpe a coleção antes: RemoveAll(b => b == null).

Uma confusão comum na desserialização é o mismatch de nomes. Se esquecer de aplicar [JsonPropertyName], a classe vai esperar a propriedade Books, mas você enviou JSON com items: como resultado a coleção não será preenchida e vai ficar vazia. Sempre verifique se os nomes batem!

8. Tabela: onde os principais atributos se aplicam

Atributo Pode ser aplicado a coleções? Pode ser aplicado a elementos de coleções? Exemplos de uso
[JsonIgnore]
sim sim Esconder a lista ou um campo dentro de Book
[JsonPropertyName]
sim sim Renomear Books → items ou Title → name
[JsonInclude]
sim sim Incluir propriedades privadas na serialização
[JsonConverter]
sim sim Atribuir um converter especial para a lista

9. Esquema de serialização de coleções com atributos


+-------------+
|   Library   |
+-------------+
  | Name           -- serializa como "Name"
  | Books          -- [JsonPropertyName("items")], serializa como "items": [...]
  | Cache          -- [JsonIgnore], não serializa
  | BookCatalog    -- [JsonPropertyName("catalog")], serializa como "catalog": {...}
Resultado JSON mais ou menos assim:
{
  "Name": "Biblioteca Municipal",
  "items": [
    {
      "Title": "1984",
      "Author": {
        "Name": "George Orwell",
        "BirthYear": 1903
      }
    },
    {
      "Title": "Grandes Esperanças",
      "Author": {
        "Name": "Charles Dickens",
        "BirthYear": 1812
      }
    }
  ],
  "catalog": {
    "978-1234567890": {
      "Title": "O Chamado de Cthulhu",
      "Author": {
        "Name": "Howard Phillips Lovecraft",
        "BirthYear": 1890
      }
    }
  }
}

10. Relevância prática e pontos em entrevistas e projetos reais

Em produção você precisa sempre considerar o contrato da API externa e os requisitos de serialização. É preciso saber “esconder” coleções internas, corresponder o casing e o estilo de nomes, e às vezes até mudar dinamicamente o esquema de serialização dependendo da versão do cliente.

Perguntas típicas em entrevistas:

  • Como serializar apenas uma parte dos dados?
  • Como fazer para uma propriedade de coleção não aparecer no JSON?
  • Como mapear nomes de propriedades entre C# e JSON quando são diferentes?
  • É possível esconder elementos individuais dentro de uma coleção da serialização (por exemplo, informações confidenciais)?

As respostas giram em torno do uso correto de atributos e opções de serialização: [JsonIgnore], [JsonPropertyName], as opções de JsonSerializerOptions e um trabalho cuidadoso com o conteúdo das coleções.

1
Pesquisa/teste
Serialização de coleções, nível 46, lição 4
Indisponível
Serialização de coleções
Serialização de objetos aninhados e hierárquicos
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION