Convertir JSON a C#
JSON a C# genera clases o records a partir de un documento de ejemplo, en tu navegador. Los nombres de las propiedades van en PascalCase y cada una lleva un atributo explícito con la clave JSON original, porque System.Text.Json distingue mayúsculas de minúsculas por defecto y una propiedad en PascalCase no se vinculará a una clave en snake_case sin que se lo digas.
El documento termina antes de tiempo; parece incompleto.
^
¿Cómo funciona Convertir JSON a C#?
C# es el destino donde la opción de tipos de referencia que admiten null cambia el aspecto de una salida correcta, así que el generador la trata como una opción de primera clase y no como una preferencia de formato.
Los tipos de referencia que admiten null deciden la forma de cada miembro
Con <Nullable>enable</Nullable>, que es el valor por defecto en todas las plantillas desde .NET 6, una propiedad string que JSON puede omitir es una advertencia a la espera de ocurrir y una NullReferenceException si ignoras la advertencia. Por eso los campos opcionales y que admiten null llevan ? — que en un tipo de valor es Nullable<T> y en un tipo de referencia es la anotación. Ambos se escriben T?, una de las cosas más elegantes del lenguaje.
Los miembros que no admiten null necesitan un inicializador o CS8618 salta en cada uno
Una propiedad obligatoria string Name { get; set; } avisa de que no está inicializada, porque el compilador no puede ver que un deserializador la va a rellenar. La respuesta convencional del código generado es = null!; — una promesa explícita al compilador de que otra cosa se la asigna. Sin ella, el archivo generado produce una advertencia por propiedad, que la gente arregla desactivando los tipos que admiten null, con lo que tira por la borda la razón de usarlos.
Los atributos son explícitos, no convenciones
System.Text.Json hace coincidir los nombres de las propiedades distinguiendo mayúsculas de minúsculas salvo configuración en contrario, así que UserId no se vincula a user_id y se queda en null en silencio. Cada propiedad lleva un [JsonPropertyName] (o [JsonProperty] para Newtonsoft) con la clave original exacta, de modo que la clase funciona sea cual sea la configuración del serializador.
class o record
Un record es la mejor opción por defecto para un payload deserializado — la igualdad por valor y un ToString legible salen gratis, y un DTO no debería mutarse después de llegar. Mucho código sigue esperando una clase mutable con propiedades asignables, así que están disponibles ambos.
long donde int truncaría
int es de 32 bits. Cualquier valor de ejemplo por encima de 2,147,483,647 — un ID snowflake, una marca de tiempo en milisegundos — se emite como long, porque un ID truncado es un bug que solo aparece cuando llegan datos reales.
Ejemplo
[
{ "user_id": 900719925474099, "name": "Ada" },
{ "user_id": 12, "name": "Grace", "team": "ops" }
]Generado
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; }
}¿Qué opciones y casos límite admite Convertir JSON a C#?
| Parámetro | Tipo | Valor predeterminado | Comportamiento y casos límite |
|---|---|---|---|
| Forma | class / record | class | record proporciona igualdad de valor y un ToString útil, lo que es adecuado para un DTO. class permanece mutable y es lo que el código antiguo espera. |
| Espacio de nombres | identificador | Generated | Envuelve la salida en un bloque de espacio de nombres. Déjalo vacío para emitir tipos sin formato para un archivo que ya tiene uno. |
| System.Text.Json | booleano | on | Emite [JsonPropertyName] y el using correspondiente. Desactívalo para [JsonProperty] y Newtonsoft.Json, que sigue siendo la opción correcta para cualquier cosa en .NET Framework. |
| nullable | booleano | on | Emite #nullable enable, marca los miembros opcionales como T?, e inicializa los miembros de referencia requeridos con = null! para que CS8618 no se active en cada propiedad. |
| string | tipo de C# | string | Los formatos detectados no se mapean a DateTime o Guid. System.Text.Json analiza ISO 8601 en DateTime si cambias el tipo manualmente, pero lanza una excepción en cualquier registro que formatee una fecha de manera diferente. |
| integer | tipo de C# | int / long | long cuando cualquier muestra supera 2,147,483,647. Los números JSON no tienen ancho declarado, por lo que se lee a partir de los valores. |
| array | tipo de C# | List<T> | List<T> en lugar de T[], porque ambos serializadores lo manejan y es lo que el código que llama suele querer. Un array de tipos mixtos se convierte en List<object>. |
| Objeto anidado | class | tipo propio | Se promueve a su propia clase, declarada antes del tipo que la utiliza. Las formas idénticas comparten una clase en lugar de generar Address, Address2, Address3. |
Preguntas frecuentes
¿Por qué cada propiedad lleva un atributo si mis claves ya están en PascalCase?
Porque la vinculación solo está garantizada con uno. System.Text.Json distingue mayúsculas de minúsculas a menos que se active PropertyNameCaseInsensitive, e incluso entonces no tenderá un puente de user_id a UserId — eso requiere una política de nombres que la clase generada no puede asumir que esté configurada. Un atributo explícito hace que la clase sea correcta con cualquier opción del serializador, y merece esa línea.
¿Qué es = null! y puedo borrarlo?
Le dice al compilador que una propiedad de referencia que no admite null será asignada por algo que él no puede ver — el deserializador — y silencia CS8618. Puedes borrarlo si declaras la propiedad como required (C# 11) o la inicializas en un constructor. Lo que no debes hacer es desactivar los tipos de referencia que admiten null para que desaparezcan las advertencias, que es la reacción habitual y tira por la borda la característica que habría detectado el null de verdad.
¿Debería usar record o class?
record para un payload que deserializas y lees: la igualdad por valor hace las pruebas mucho más limpias y la inmutabilidad es lo correcto para datos que llegaron de otro sitio. class si el objeto se va a mutar, si trabajas con un framework anterior a C# 9 o si una base de código existente espera propiedades asignables en todas partes.
¿Por qué mi fecha es un string?
Porque generar un DateTime a partir del ejemplo produciría una clase que lanza una excepción con el primer registro cuya fecha tenga otro formato. System.Text.Json solo acepta ISO 8601, y las API reales emiten marcas de tiempo Unix, fechas en formato estadounidense y offsets sin dos puntos. El formato detectado se indica, de modo que puedas cambiar el tipo a conciencia, con un convertidor si el formato lo necesita.
¿Newtonsoft o System.Text.Json?
System.Text.Json para cualquier cosa en .NET moderno — viene de serie, es bastante más rápido y es hacia donde va la inversión. Newtonsoft si estás en .NET Framework, o si dependes de algo que System.Text.Json todavía no hace: TypeNameHandling, contract resolvers personalizados, o el parseo más indulgente de entrada malformada. El generador emite los atributos correctos en cualquier caso.
¿Se sube mi JSON?
No. El documento se analiza, los tipos se infieren y el código se dibuja en la pestaña que ya tienes abierta. Puedes comprobarlo en el panel Network. Esto importa por la razón de siempre: los ejemplos que la gente pega en un generador de clases son respuestas reales, muchas veces con datos de clientes todavía dentro.