Pular para o conteúdo principal

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.

Só local
Estrutura
JSON de exemplo
0 B1 linhaLin. 1, Col. 1
Erro de sintaxe · Erro na linha 1, coluna 1

O documento termina cedo demais — parece incompleto.


^
Código geradosomente leitura
0 B1 linha
Se possível, cole mais de um registro. Assim, campos opcionais ausentes em algumas linhas podem ser detectados.

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?

Referência técnica e opções
ParâmetroTipoPadrãoComportamento e casos-limite
Formatoclass / recordclassrecord 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.
NamespaceidentificadorGeneratedEnvolve 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.JsonbooleanoonEmite [JsonPropertyName] e o using correspondente. Desligue para [JsonProperty] e Newtonsoft.Json, que ainda é a escolha certa para qualquer coisa no .NET Framework.
nullablebooleanoonEmite #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.
stringtipo C#stringFormatos 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.
inteirotipo C#int / longlong 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.
arraytipo 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 aninhadoclassetipo próprioPromovido 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.