100 % local: tus datos nunca salen de tu navegador

JSON a C# — records que System.Text.Json lee

Convierte una muestra JSON en records o clases de C#. Cada propiedad renombrada lleva un atributo JsonPropertyName: el deserializador encuentra su clave.

Instantáneo Privado Cero cookies
Estilo

Entrada JSON

Salida C#

Qué hace esta herramienta

Una muestra JSON pasa a ser records de C#, uno por objeto.

{ "id": 1, "firstName": "Ada", "address": { "city": "Paris" } }
using System.Text.Json.Serialization;

public record Root(
    [property: JsonPropertyName("id")] long Id,
    [property: JsonPropertyName("firstName")] string FirstName,
    [property: JsonPropertyName("address")] Address Address
);

public record Address(
    [property: JsonPropertyName("city")] string City
);

Los records posicionales piden C# 9; el using aparece solo si aparece un atributo.

El destino del atributo importa

Los nombres de propiedad de C# van en PascalCase: firstName pasa a FirstName, y content-type pasa a ContentType. System.Text.Json compara sin distinguir mayúsculas solo si se lo pides, y nunca a través de un guion: por eso la clave se fija con un atributo.

El prefijo property: es la parte fácil de fallar. En un record posicional, el parámetro no es la propiedad: un atributo sin destino se queda en el parámetro del constructor, y el serializador no lo ve nunca. Con el destino, cae donde se lee.

Los tipos

  • Los enteros pasan a long y los decimales a double, ambos más anchos que el valor por defecto de 32 bits, porque un número JSON no promete caber ahí.
  • null y los valores desconocidos pasan a object?, lo que supone tener activados los tipos de referencia anulables (el valor por defecto desde .NET 6).
  • Los arrays pasan a List<T>; uno mezclado pasa a List<object>, salvo si mezcla enteros y decimales: entonces List<double> cubre ambos.
  • Un escalar en la raíz se rechaza: C# no tiene alias de tipo global, así que 42 no tiene en qué convertirse. Un array de objetos te da el record de su elemento, el que enlazas a una List<Root>.

Lo que una muestra no puede decir

Ninguna propiedad admite nulos más allá de esos object?, y ninguna tiene valor por defecto: el documento traía un valor para cada una. required e init merecen añadirse cuando sepas qué claves son de verdad obligatorias; una muestra solo puede decirte cuáles estaban.

Privado por diseño

Todo se ejecuta localmente en tu navegador con JavaScript. Tus datos nunca se suben a un servidor, lo que hace que la herramienta sea segura para contenido sensible y funcione sin conexión.

Preguntas frecuentes

¿Por qué `[property: JsonPropertyName(...)]` y no solo `[JsonPropertyName(...)]`?
Porque un parámetro de record posicional todavía no es una propiedad. Sin el destino `property:`, el atributo cae en el parámetro del constructor, donde el serializador nunca mira; el compilador incluso avisa. El destino lo mueve a la propiedad generada, que es donde `System.Text.Json` lo lee.
Uso Newtonsoft.Json. ¿Qué cambio?
El atributo y su using: `[property: JsonProperty("content-type")]` con `Newtonsoft.Json`. Nada más difiere: nombres de propiedad, tipos y forma del record son iguales. Newtonsoft además compara sin distinguir mayúsculas por defecto, así que las claves en `camelCase` suelen funcionar sin atributo alguno.
¿Record o clase?
El record es el valor por defecto: igualdad por valor, expresiones `with` y un constructor que hace explícito cada campo al crear. La opción de clase da propiedades asignables, que es lo que espera una base más antigua o un framework que construye objetos por asignación. Los tipos inferidos son idénticos.

Convertidores relacionados