Converter JSON em C#
Esta ferramenta gera classes ou records a partir de um documento de exemplo no seu navegador. Os nomes de propriedades ficam em PascalCase e cada um carrega um atributo explícito com a chave JSON original, porque o System.Text.Json diferencia maiúsculas de minúsculas por padrão e uma propriedade em PascalCase não faz bind a uma chave em snake_case sem ser configurada para isso.
O documento termina cedo demais — parece incompleto.
^
Como funciona o Converter JSON em C#?
C# é o alvo em que a configuração de nullable reference types muda como é a saída correta, então o gerador a trata como uma opção de primeira classe, e não como uma preferência de formatação.
Nullable reference types decidem a forma de cada membro
Com <Nullable>enable</Nullable>, que é o padrão em todos os templates desde o .NET 6, uma propriedade string que o JSON pode deixar ausente é um aviso esperando para acontecer e uma NullReferenceException se o aviso for ignorado. Campos opcionais e anuláveis, portanto, recebem ? — que em um value type é Nullable<T> e em um reference type é a anotação. Ambos se escrevem T?, o que é uma das coisas mais elegantes da linguagem.
Membros não anuláveis precisam de um inicializador, ou o CS8618 dispara em cada um deles
Uma propriedade obrigatória string Name { get; set; } gera o aviso de que não foi inicializada, porque o compilador não consegue ver que um desserializador vai preenchê-la. A resposta convencional em código gerado é = null!; — uma promessa explícita ao compilador de que outra coisa fará a atribuição. Sem ela, o arquivo gerado produz um aviso por propriedade, que as pessoas resolvem desligando nullable, o que joga fora a razão de usá-lo.
Atributos são explícitos, não convenções
O System.Text.Json compara nomes de propriedades diferenciando maiúsculas de minúsculas, a menos que configurado de outra forma, então UserId não faz bind com user_id e fica null em silêncio. Toda propriedade recebe um [JsonPropertyName] (ou [JsonProperty] no Newtonsoft) carregando a chave original exata, então a classe funciona independentemente das opções do serializador.
class ou record
Um record é o padrão melhor para uma carga desserializada — igualdade por valor e um ToString legível vêm de graça, e um DTO não deveria ser mutado depois de chegar. Muito código ainda espera uma classe mutável com propriedades setáveis, então ambos estão disponíveis.
long onde int truncaria
int é de 32 bits. Qualquer valor de exemplo além de 2,147,483,647 — um ID snowflake, um timestamp em milissegundos — é emitido como long, porque um ID truncado é um bug que só aparece quando os dados reais chegam.
Exemplo
[
{ "user_id": 900719925474099, "name": "Ada" },
{ "user_id": 12, "name": "Grace", "team": "ops" }
]Gerado
public class User
{
[JsonPropertyName("user_id")]
public long UserId { get; set; }
[JsonPropertyName("name")]
public string Name { get; set; } = null!;
[JsonPropertyName("team")]
public string? Team { get; set; }
}Quais opções e casos-limite o Converter JSON em C# suporta?
| Parâmetro | Tipo | Padrão | Comportamento e casos-limite |
|---|---|---|---|
| Formato | class / record | class | record dá igualdade de valor e um ToString útil, o que se adequa a um DTO. class permanece mutável e é o que o código mais antigo espera. |
| Namespace | identificador | Generated | Envolve a saída em um bloco de namespace. Deixe-o em branco para emitir tipos brutos para um arquivo que já tem um. |
| System.Text.Json | booleano | on | Emite [JsonPropertyName] e o using correspondente. Desligue para [JsonProperty] e Newtonsoft.Json, que ainda é a escolha certa para qualquer coisa no .NET Framework. |
| nullable | booleano | on | Emite #nullable enable, marca membros opcionais como T?, e inicializa membros de referência obrigatórios com = null! para que CS8618 não acione em todas as propriedades. |
| string | tipo C# | string | Formatos detectados não são mapeados para DateTime ou Guid. System.Text.Json analisa ISO 8601 em DateTime se você alterar o tipo manualmente, mas ele lança um erro em qualquer registro que formate uma data de forma diferente. |
| inteiro | tipo C# | int / long | long quando qualquer amostra excede 2,147,483,647. Números JSON não têm largura declarada, então isso é lido a partir dos valores. |
| array | tipo C# | List<T> | List<T> em vez de T[], porque ambos os serializadores lidam com isso e é o que o código de chamada geralmente quer. Um array de tipos mistos se torna List<object>. |
| Objeto aninhado | classe | tipo próprio | Promovido para sua própria classe, declarada antes do tipo que a usa. Formatos idênticos compartilham uma classe em vez de gerar Address, Address2, Address3. |
Perguntas frequentes
Por que toda propriedade tem um atributo quando minhas chaves já estão em PascalCase?
Porque o bind só é garantido com um. O System.Text.Json diferencia maiúsculas de minúsculas a menos que PropertyNameCaseInsensitive esteja definido, e mesmo assim ele não faz a ponte de user_id para UserId — isso exige uma naming policy que a classe gerada não pode presumir estar configurada. Um atributo explícito deixa a classe correta sob quaisquer opções de serializador, o que vale a linha.
O que é = null! e posso apagar?
Ele diz ao compilador que uma propriedade de referência não anulável será atribuída por algo que ele não enxerga — o desserializador — e suprime o CS8618. Você pode apagar se tornar a propriedade required (C# 11) ou inicializá-la em um construtor. O que você não deve fazer é desligar nullable reference types para fazer os avisos sumirem, que é a reação usual e joga fora justamente o recurso que teria capturado o null real.
Devo usar record ou class?
record para uma carga que você desserializa e lê: igualdade por valor deixa os testes bem mais limpos, e imutabilidade é o correto para dados que chegaram de outro lugar. class se o objeto vai ser mutado, se você está em um framework anterior ao C# 9, ou se uma base de código existente espera propriedades setáveis em toda parte.
Por que minha data é uma string?
Porque gerar DateTime a partir de uma amostra produziria uma classe que lança exceção no primeiro registro cuja data vier formatada de outra forma. O System.Text.Json só aceita ISO 8601, e APIs reais emitem timestamps Unix, datas em formato americano e offsets sem dois-pontos. O formato detectado é indicado para que você possa mudar o tipo de propósito, com um converter se o formato exigir um.
Newtonsoft ou System.Text.Json?
System.Text.Json para qualquer coisa em .NET moderno — ele já vem na caixa, é significativamente mais rápido e é onde o investimento está indo. Newtonsoft se você está no .NET Framework, ou se depende de algo que o System.Text.Json ainda não faz: TypeNameHandling, contract resolvers personalizados, ou a análise mais tolerante de entrada malformada. De qualquer forma, o gerador emite os atributos corretos.
Meu JSON é enviado?
Não. O documento é analisado, os tipos são inferidos e o código é renderizado na aba que você já tem aberta. Você pode confirmar isso no painel Network. Isso importa pelo motivo de sempre: as amostras que as pessoas colam em um gerador de classes são respostas reais, frequentemente com dados de clientes ainda nelas.