C#: JSON e serialização
1. Noções básicas sobre o formato JSON
JSON (JavaScript Object Notation) é um formato leve de intercâmbio de dados que armazena e transmite dados estruturados como texto simples.
- Objeto: Envolvido em
{}, contém pares chave-valor; as chaves devem ser strings - Matriz: Envolvida em
[], uma lista ordenada de valores - Tipos de dados: String, número, booleano, nulo, objeto, matriz
{
"name": "Zhang San",
"age": 28,
"isStudent": false,
"hobbies": ["programming", "reading"],
"address": {
"city": "Beijing",
"zip": "100000"
}
}
2. Visão geral do System.Text.Json
System.Text.Json é uma biblioteca JSON de alto desempenho integrada ao .NET Core 3.0+, que não requer pacotes de terceiros. É recomendada em vez da Newtonsoft.Json.
using System.Text.Json;
3. Serialização: de objeto para JSON
JsonSerializer.Serialize() converte um objeto em uma string JSON.
▶ Exemplo
using System;
using System.Text.Json;
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public bool IsStudent { get; set; }
}
class Program
{
static void Main()
{
var person = new Person
{
Name = "Zhang San",
Age = 28,
IsStudent = false
};
string json = JsonSerializer.Serialize(person);
Console.WriteLine(json);
}
}
{"Name":"Zhang San","Age":28,"IsStudent":false}
4. Deserialização: de JSON para objeto
JsonSerializer.Deserialize``<T>``() converte uma string JSON de volta em um objeto do tipo especificado.
▶ Exemplo
using System;
using System.Text.Json;
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public bool IsStudent { get; set; }
}
class Program
{
static void Main()
{
string json = @"{""Name"":""Zhang San"",""Age"":28,""IsStudent"":false}";
Person person = JsonSerializer.Deserialize<Person>(json);
Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");
}
}
Name: Zhang San, Age: 28
5. Configuração do JsonSerializerOptions
Use JsonSerializerOptions para controlar o comportamento da serialização, como a política de nomenclatura, a indentação e a ignorância de valores nulos.
| Opção | Descrição |
|---|---|
PropertyNamingPolicy |
Política de nomenclatura de propriedades, por exemplo, JsonNamingPolicy.CamelCase |
WriteIndented |
Se a saída deve ser recuada para facilitar a leitura |
IgnoreNullValues |
Se as propriedades com valor nulo devem ser ignoradas |
PropertyNameCaseInsensitive |
Ignorar maiúsculas e minúsculas nos nomes das propriedades durante a desserialização |
▶ Exemplo
using System;
using System.Text.Json;
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public string Email { get; set; }
}
class Program
{
static void Main()
{
var person = new Person
{
Name = "Zhang San",
Age = 28,
Email = null
};
var options = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = true,
IgnoreNullValues = true
};
string json = JsonSerializer.Serialize(person, options);
Console.WriteLine(json);
}
}
{
"name": "Zhang San",
"age": 28
}
6. Serialização de coleções e dicionários
JsonSerializer pode serializar diretamente tipos de coleção, como listas e dicionários.
▶ Exemplo
using System;
using System.Collections.Generic;
using System.Text.Json;
public class Student
{
public string Name { get; set; }
public int Score { get; set; }
}
class Program
{
static void Main()
{
var students = new List<Student>
{
new Student { Name = "Zhang San", Score = 90 },
new Student { Name = "Li Si", Score = 85 },
new Student { Name = "Wang Wu", Score = 92 }
};
var options = new JsonSerializerOptions { WriteIndented = true };
string json = JsonSerializer.Serialize(students, options);
Console.WriteLine(json);
var scores = new Dictionary`<string, int>`
{
["Chinese"] = 90,
["Math"] = 95,
["English"] = 88
};
string dictJson = JsonSerializer.Serialize(scores, options);
Console.WriteLine(dictJson);
}
}
[
{
"Name": "Zhang San",
"Score": 90
},
{
"Name": "Li Si",
"Score": 85
},
{
"Name": "Wang Wu",
"Score": 92
}
]
{
"Chinese": 90,
"Math": 95,
"English": 88
}
7. JSON dinâmico: JsonDocument e JsonElement
Quando a estrutura JSON é incerta, você pode usar JsonDocument e JsonElement para realizar uma análise dinâmica sem classes predefinidas.
▶ Exemplo
using System;
using System.Text.Json;
class Program
{
static void Main()
{
string json = @"{""name"":""Zhang San"",""age"":28,""hobbies"":[""programming"",""reading""]}";
using JsonDocument doc = JsonDocument.Parse(json);
JsonElement root = doc.RootElement;
string name = root.GetProperty("name").GetString();
int age = root.GetProperty("age").GetInt32();
JsonElement hobbies = root.GetProperty("hobbies");
Console.WriteLine($"Name: {name}, Age: {age}");
foreach (JsonElement hobby in hobbies.EnumerateArray())
{
Console.WriteLine($"Hobby: {hobby.GetString()}");
}
}
}
Name: Zhang San, Age: 28
Hobby: programming
Hobby: reading
8. Serialização personalizada: JsonConverter
Herdar de JsonConverter<T> e sobrescrever os métodos Read e Write para implementar uma lógica personalizada de serialização/desserialização.
▶ Exemplo
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
public class DateOnlyConverter : JsonConverter`<DateTime>`
{
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return DateTime.ParseExact(reader.GetString(), "yyyy-MM-dd", null);
}
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToString("yyyy-MM-dd"));
}
}
public class Event
{
public string Title { get; set; }
[JsonConverter(typeof(DateOnlyConverter))]
public DateTime Date { get; set; }
}
class Program
{
static void Main()
{
var evt = new Event
{
Title = "Product Launch",
Date = new DateTime(2025, 6, 15)
};
string json = JsonSerializer.Serialize(evt);
Console.WriteLine(json);
Event deserialized = JsonSerializer.Deserialize<Event>(json);
Console.WriteLine($"Title: {deserialized.Title}, Date: {deserialized.Date:yyyy-MM-dd}");
}
}
{"Title":"Product Launch","Date":"2025-06-15"}
Title: Product Launch, Date: 2025-06-15
9. Combinando JSON com LINQ
Após deserializar o JSON em uma coleção, você pode usar o LINQ para realizar consultas, filtragens e agregações.
▶ Exemplo
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
public class Student
{
public string Name { get; set; }
public int Score { get; set; }
public string City { get; set; }
}
class Program
{
static void Main()
{
string json = @"[
{""Name"":""Zhang San"",""Score"":90,""City"":""Beijing""},
{""Name"":""Li Si"",""Score"":85,""City"":""Shanghai""},
{""Name"":""Wang Wu"",""Score"":92,""City"":""Beijing""},
{""Name"":""Zhao Liu"",""Score"":78,""City"":""Shanghai""},
{""Name"":""Qian Qi"",""Score"":95,""City"":""Beijing""}
]";
List<Student> students = JsonSerializer.Deserialize<List<Student>>(json);
var beijingTop = students
.Where(s => s.City == "Beijing")
.OrderByDescending(s => s.Score)
.ToList();
Console.WriteLine("Beijing students (sorted by score, descending):");
foreach (var s in beijingTop)
{
Console.WriteLine($" {s.Name}: {s.Score}");
}
var cityAvg = students
.GroupBy(s => s.City)
.Select(g => new { City = g.Key, Avg = g.Average(s => s.Score) });
Console.WriteLine("\nAverage score by city:");
foreach (var item in cityAvg)
{
Console.WriteLine($" {item.City}: {item.Avg:F1}");
}
}
}
Beijing students (sorted by score, descending):
Qian Qi: 95
Wang Wu: 92
Zhang San: 90
Average score by city:
Beijing: 92.3
Shanghai: 81.5
10. Introdução à leitura e gravação de arquivos CSV
CSV (Comma-Separated Values) é um formato de texto que separa os campos por vírgulas, comumente usado para exportação e troca de dados. A biblioteca padrão do C# não oferece suporte integrado a CSV; você pode analisá-lo manualmente ou usar uma biblioteca de terceiros, como CsvHelper.
▶ Exemplo
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
class Program
{
static void Main()
{
var records = new List<string[]>
{
new[] { "Name", "Age", "City" },
new[] { "Zhang San", "28", "Beijing" },
new[] { "Li Si", "25", "Shanghai" }
};
string csvPath = "data.csv";
File.WriteAllLines(csvPath, records.Select(r => string.Join(",", r)));
string[] lines = File.ReadAllLines(csvPath);
foreach (string line in lines)
{
string[] fields = line.Split(',');
Console.WriteLine($"{fields[0],-10} {fields[1],-4} {fields[2]}");
}
}
}
Name Age City
Zhang San 28 Beijing
Li Si 25 Shanghai
💡 Dica: Para ambientes de produção, recomenda-se usar o CsvHelper (pacote NuGet), que lida corretamente com campos que contêm vírgulas, aspas e quebras de linha, evitando erros comuns da análise manual.
❓ Perguntas Frequentes
P: Qual é a diferença entre System.Text.Json e Newtonsoft.Json? R: System.Text.Json é uma biblioteca de alto desempenho integrada ao .NET, enquanto Newtonsoft.Json é uma biblioteca de terceiros com recursos mais abrangentes. Em novos projetos, deve-se dar preferência à biblioteca integrada.
P: E se os nomes das propriedades apresentarem diferenças de maiúsculas e minúsculas durante a desserialização? R: Defina
PropertyNameCaseInsensitive = trueemJsonSerializerOptionspara ignorar as diferenças de maiúsculas e minúsculas.
P: Como faço para excluir uma propriedade da serialização? R: Adicione o atributo
[JsonIgnore]a essa propriedade para ignorá-la.
P: Como faço para controlar o formato de data no JSON? R: Crie um
JsonConverter<DateTime>personalizado e sobrescreva o método Write para especificar a string de formato de data desejada.
📖 Resumo
- O JSON utiliza
{}para objetos e[]para matrizes; trata-se de um formato universal de intercâmbio de dados System.Text.Jsoné a biblioteca JSON integrada do .NET, que utilizaSerialize/Deserializepara a conversãoJsonSerializerOptionsconfigura a política de nomenclatura, a indentação, o tratamento de valores nulos e muito maisJsonDocument/JsonElementsão adequados para analisar JSON com estrutura incerta- O
JsonConverter<T>personalizado controla a lógica de serialização para tipos específicos - Dados JSON deserializados em coleções podem ser combinados com o LINQ para consultas e agregações
- O CSV pode ser analisado manualmente; para uso em produção, recomenda-se a biblioteca
CsvHelper
📝 Exercícios
- Defina uma classe
Book(Título, Autor, Preço, EstáPublicado), serialize-a em uma string JSON com indentação e exiba-a; em seguida, deserialize-a de volta para um objeto - Crie um
List<Book>com pelo menos 3 livros, converta-o para JSON e, em seguida, use o LINQ para filtrar os livros cujo preço seja superior a 50 - Escreva um
JsonConverterpersonalizado que serializeDateTimeno formato"yyyy/MM/dd"e verifique se a desserialização o restaura corretamente - Serializar um
Dictionary<string, string>para JSON e salvá-lo em um arquivo; em seguida, ler o arquivo e deserializá-lo novamente - Escreva uma lógica manual de leitura/gravação de CSV que lide com campos contendo vírgulas (coloque-os entre aspas duplas)