JSONをC#に変換
JSON to C# generates classes or records from a sample document in your browser. Property names are PascalCase and every one carries an explicit attribute with the original JSON key, because System.Text.Json is case-sensitive by default and a PascalCase property will not bind to a snake_case key without being told to.
このツールの画面は英語表記です。
Empty JSON input (truncated document)
^
以下の解説は英語のみでご覧いただけます。
How does JSON to C# Classes work?
C# is the target where the nullable reference type setting changes what correct output looks like, so the generator treats it as a first-class option rather than a formatting preference.
Nullable reference types decide the shape of every member
Under <Nullable>enable</Nullable>, which is the default on every template since .NET 6, a string property that JSON can leave absent is a warning waiting to happen and a NullReferenceException if the warning is ignored. Optional and nullable fields therefore get ? — which on a value type is Nullable<T> and on a reference type is the annotation. Both are spelled T?, which is one of the tidier things about the language.
Non-nullable members need an initialiser or CS8618 fires on every one
A required string Name { get; set; } warns that it is uninitialised, because the compiler cannot see that a deserializer will fill it. The conventional generated-code answer is = null!; — an explicit promise to the compiler that something else assigns it. Without it the generated file produces one warning per property, which people fix by turning nullable off, which throws away the reason to use it.
Attributes are explicit, not conventions
System.Text.Json matches property names case-sensitively unless configured otherwise, so UserId does not bind to user_id and quietly stays null. Every property gets a [JsonPropertyName] (or [JsonProperty] for Newtonsoft) carrying the exact original key, so the class works regardless of what the serializer options happen to be.
class or record
A record is the better default for a deserialized payload — value equality and a readable ToString come free, and a DTO should not be mutated after it arrives. Plenty of code still expects a mutable class with settable properties, so both are available.
long where int would truncate
int is 32-bit. Any sample value beyond 2,147,483,647 — a snowflake ID, a millisecond timestamp — is emitted as long, because a truncated ID is a bug that only appears once real data arrives.
Sample
[
{ "user_id": 900719925474099, "name": "Ada" },
{ "user_id": 12, "name": "Grace", "team": "ops" }
]Generated
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; }
}What options and edge cases does JSON to C# Classes support?
| Parameter | Type | Default | Behaviour & edge cases |
|---|---|---|---|
| Shape | class / record | class | record gives value equality and a useful ToString, which suits a DTO. class stays mutable and is what older code expects. |
| Namespace | identifier | Generated | Wraps the output in a namespace block. Leave it empty to emit bare types for a file that already has one. |
| System.Text.Json | boolean | on | Emits [JsonPropertyName] and the matching using. Turn it off for [JsonProperty] and Newtonsoft.Json, which is still the right choice for anything on .NET Framework. |
| nullable | boolean | on | Emits #nullable enable, marks optional members T?, and initialises required reference members with = null! so CS8618 does not fire on every property. |
| string | C# type | string | Detected formats are not mapped to DateTime or Guid. System.Text.Json parses ISO 8601 into DateTime if you change the type by hand, but it throws on any record that formats a date differently. |
| integer | C# type | int / long | long when any sample exceeds 2,147,483,647. JSON numbers have no declared width, so this is read from the values. |
| array | C# type | List<T> | List<T> rather than T[], because both serializers handle it and it is what calling code usually wants. An array of mixed types becomes List<object>. |
| Nested object | class | own type | Promoted to its own class, declared before the type that uses it. Identical shapes share one class rather than generating Address, Address2, Address3. |
Frequently asked questions
Why does every property have an attribute when my keys are already PascalCase?
Because the binding is only guaranteed with one. System.Text.Json matches case-sensitively unless PropertyNameCaseInsensitive is set, and even then it will not bridge user_id to UserId — that needs a naming policy the generated class cannot assume is configured. An explicit attribute makes the class correct under any serializer options, which is worth the line.
What is = null! and can I delete it?
It tells the compiler that a non-nullable reference property will be assigned by something it cannot see — the deserializer — and suppresses CS8618. You can delete it if you make the property required (C# 11) or initialise it in a constructor. What you should not do is turn nullable reference types off to make the warnings go away, which is the usual reaction and throws away the feature that would have caught the real null.
Should I use record or class?
record for a payload you deserialize and read: value equality makes tests much cleaner and immutability is correct for data that arrived from elsewhere. class if the object is going to be mutated, if you are on a framework older than C# 9, or if an existing codebase expects settable properties everywhere.
Why is my date a string?
Because generating DateTime from a sample would produce a class that throws on the first record whose date is formatted differently. System.Text.Json only accepts ISO 8601, and real APIs emit Unix timestamps, US-format dates and offsets-without-colons. The detected format is noted so you can change the type deliberately, with a converter if the format needs one.
Newtonsoft or System.Text.Json?
System.Text.Json for anything on modern .NET — it is in the box, it is significantly faster, and it is where the investment is going. Newtonsoft if you are on .NET Framework, or if you depend on something System.Text.Json still does not do: TypeNameHandling, custom contract resolvers, or the more forgiving parsing of malformed input. The generator emits the right attributes either way.
Is my JSON uploaded?
No. The document is parsed, the types are inferred and the code is rendered in the tab you already have open. You can confirm it in the Network panel. This matters for the usual reason: the samples people paste into a class generator are real responses, frequently with customer data still in them.