100 % local — vos données ne quittent jamais votre navigateur

JSON en C# — des records que System.Text.Json lit

Transformez un échantillon JSON en records ou classes C#. Chaque propriété renommée porte un attribut JsonPropertyName : le désérialiseur retrouve sa clé.

Instantané Privé Zéro cookie
Style

Entrée JSON

Sortie C#

Ce que fait cet outil

Un échantillon JSON devient des records C#, un par objet.

{ "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
);

Les records positionnels demandent C# 9 ; le using n’apparaît que si un attribut apparaît.

La cible de l’attribut compte

Les noms de propriétés C# sont en PascalCase : firstName devient FirstName, et content-type devient ContentType. System.Text.Json ne compare sans tenir compte de la casse que si vous le lui demandez, et jamais à travers un tiret — la clé est donc fixée par un attribut.

Le préfixe property: est la partie facile à rater. Sur un record positionnel, le paramètre n’est pas la propriété : un attribut sans cible reste sur le paramètre du constructeur, et le sérialiseur ne le voit jamais. Avec la cible, il atterrit là où il est lu.

Les types

  • Les entiers deviennent long, les décimaux double — tous deux plus larges que le défaut 32 bits, parce qu’un nombre JSON ne promet pas d’y tenir.
  • null et les valeurs inconnues deviennent object?, ce qui suppose les types référence nullables activés (le défaut depuis .NET 6).
  • Les tableaux deviennent List<T> ; un tableau mêlé devient List<object>, sauf s’il mêle entiers et décimaux : List<double> couvre alors les deux.
  • Un scalaire à la racine est refusé : C# n’a pas d’alias de type global, 42 n’a donc rien à devenir. Un tableau d’objets vous rend le record de son élément, celui que vous liez à une List<Root>.

Ce qu’un échantillon ne peut pas dire

Aucune propriété n’est nullable au-delà de ces object?, et aucune n’a de valeur par défaut : le document avait une valeur pour chacune. required et init valent d’être ajoutés quand vous saurez quelles clés sont vraiment obligatoires — un échantillon ne peut dire que lesquelles étaient là.

Confidentiel par conception

Tout s’exécute localement dans votre navigateur en JavaScript. Vos données ne sont jamais envoyées sur un serveur, ce qui rend l’outil sûr pour des contenus sensibles, et il fonctionne hors ligne.

Questions fréquentes

Pourquoi `[property: JsonPropertyName(...)]` et pas simplement `[JsonPropertyName(...)]` ?
Parce qu’un paramètre de record positionnel n’est pas encore une propriété. Sans la cible `property:`, l’attribut atterrit sur le paramètre du constructeur, là où le sérialiseur ne regarde jamais — le compilateur émet même un avertissement. La cible le déplace sur la propriété engendrée, où `System.Text.Json` le lit.
J’utilise Newtonsoft.Json. Que faut-il changer ?
L’attribut et son using : `[property: JsonProperty("content-type")]` avec `Newtonsoft.Json`. Rien d’autre ne diffère — noms de propriétés, types et forme du record sont identiques. Newtonsoft compare aussi sans tenir compte de la casse par défaut : des clés en `camelCase` passent donc souvent sans aucun attribut.
Record ou classe ?
Le record est le défaut : égalité par valeur, expressions `with`, et un constructeur qui rend chaque champ explicite à la création. L’option classe donne des propriétés affectables, ce qu’attend une base plus ancienne ou un cadre qui construit les objets par affectation. Les types inférés sont identiques.

Convertisseurs associés