JSONからC#クラスへの変換は、現代の.NET開発において不可欠なタスクです。ASP.NET Core Web API、Unityゲーム、Blazorアプリ、MAUIモバイルクライアントのいずれを構築する場合でも、JSONレスポンスをデシリアライズするために強く型付けされたC#クラスが必要です。このガイドでは、型マッピング、System.Text.Json、Newtonsoft.Json、record型、POCO生成、ベストプラクティスをカバーします。
無料オンラインJSON to C#クラスコンバーターをお試しください。
JSON to C#クラス変換とは?
JSONはWeb API、クラウドサービス、設定システムの共通データ交換フォーマットです。C#は静的型付け言語であり、明示的なクラス定義が必要です。JSON to C#クラス変換はJSONドキュメントを分析し、適切に型付けされたプロパティとシリアル化属性を持つ対応するC#クラスを生成します。
典型的なASP.NET Coreアプリケーションでは、コントローラーがJSON文字列としてHTTPリクエストボディを受信します。フレームワークはSystem.Text.JsonまたはNewtonsoft.Jsonを使用してJSONをC#オブジェクトに変換する必要があります。
Unity、Blazor、Azure Functionsでも同じ変換が必要です。プロセスは同一です:JSON構造の検査、型決定、ネストと配列の処理。
JSON to C#:型マッピング
JSONの型がC#の型にどのようにマッピングされるかを理解することが変換の基盤です:
| JSON型 | 例 | C#型 | 備考 |
|---|---|---|---|
| string | "hello" | string | 常にSystem.String |
| number(整数) | 42 | int、long | null可能時はint? |
| number(小数) | 3.14 | double、decimal | 金融データにはdecimal |
| boolean | true | bool | null可能時はbool? |
| null | null | null | Nullable型 |
| array | [1,2] | List<T> | List推奨 |
| object | {"k":"v"} | ネストクラス | 強い型付けクラス推奨 |
JSONからC#クラスを生成する際、値型とNullable型の選択が重要です。金額には常にdecimalを使用してください。
JSON to C#変換の仕組み
JSON to C#クラスコンバーターは体系的なプロセスに従います:
- JSON構造を解析:構文木を構築。
- プロパティ型を推論:各プロパティのC#型を決定。
- 名前を生成:PascalCaseに変換。
- ネストオブジェクトを処理:各ネストオブジェクトが別クラスを生成。
- 配列を処理:要素型を分析。
- 属性を追加:
[JsonPropertyName]または[JsonProperty]。 - ソースコードを出力:フォーマットされたC#コード。
コード例:System.Text.JsonとNewtonsoftでJSON to C#
System.Text.Json(.NET 8+):JsonSerializerと属性
System.Text.Jsonは.NET組み込みの高性能JSONシリアライザーです。.NET 8からAOTコンパイル用のソースジェネレーターをサポートします:
// === Sample JSON ===
// {
// "user_id": 1001,
// "user_name": "Alice",
// "email": "alice@example.com",
// "is_active": true,
// "balance": 1250.75,
// "tags": ["admin", "developer"],
// "address": {
// "street": "123 Main St",
// "city": "Springfield",
// "zip_code": "62704"
// }
// }
// === C# class with System.Text.Json attributes ===
using System.Text.Json;
using System.Text.Json.Serialization;
public class User
{
[JsonPropertyName("user_id")]
public long UserId { get; set; }
[JsonPropertyName("user_name")]
public string UserName { get; set; } = "";
public string Email { get; set; } = "";
[JsonPropertyName("is_active")]
public bool IsActive { get; set; }
public decimal Balance { get; set; }
public List<string> Tags { get; set; } = new();
public Address Address { get; set; } = new();
}
public class Address
{
public string Street { get; set; } = "";
public string City { get; set; } = "";
[JsonPropertyName("zip_code")]
public string ZipCode { get; set; } = "";
}
// === Deserialization with JsonSerializer ===
var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};
// Single object
User? user = JsonSerializer.Deserialize<User>(jsonString, options);
// List of objects
List<User>? users = JsonSerializer.Deserialize<List<User>>(
jsonArrayString, options);
// === Custom JsonConverter for special cases ===
public class EpochToDateTimeConverter : JsonConverter<DateTime>
{
public override DateTime Read(
ref Utf8JsonReader reader, Type typeToConvert,
JsonSerializerOptions options)
{
return DateTimeOffset.FromUnixTimeSeconds(
reader.GetInt64()).DateTime;
}
public override void Write(
Utf8JsonWriter writer, DateTime value,
JsonSerializerOptions options)
{
writer.WriteNumberValue(
new DateTimeOffset(value).ToUnixTimeSeconds());
}
}
// Usage: [JsonConverter(typeof(EpochToDateTimeConverter))]
// public DateTime CreatedAt { get; set; }
// === .NET 8 Source Generator (AOT-friendly) ===
[JsonSerializable(typeof(User))]
[JsonSerializable(typeof(List<User>))]
public partial class AppJsonContext : JsonSerializerContext { }
// Zero-reflection deserialization:
User? u = JsonSerializer.Deserialize(
jsonString, AppJsonContext.Default.User);Newtonsoft.Json:JsonConvertと属性
Newtonsoft.JsonはC# JSONデシリアライゼーションの事実上の標準ライブラリです。JObject、LINQ-to-JSON、カスタムJsonConverterを提供します:
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
public class User
{
[JsonProperty("user_id")]
public long UserId { get; set; }
[JsonProperty("user_name")]
public string UserName { get; set; } = "";
public string Email { get; set; } = "";
[JsonProperty("is_active")]
public bool IsActive { get; set; }
public decimal Balance { get; set; }
public List<string> Tags { get; set; } = new();
public Address Address { get; set; } = new();
}
// === Deserialization with JsonConvert ===
var settings = new JsonSerializerSettings
{
MissingMemberHandling = MissingMemberHandling.Ignore,
NullValueHandling = NullValueHandling.Ignore,
DateFormatString = "yyyy-MM-ddTHH:mm:ssZ"
};
// Single object
User? user = JsonConvert.DeserializeObject<User>(
jsonString, settings);
// List of objects
List<User>? users = JsonConvert.DeserializeObject<List<User>>(
jsonArrayString, settings);
// === Dynamic parsing with JObject ===
JObject obj = JObject.Parse(jsonString);
string? name = (string?)obj["user_name"];
JArray? tags = (JArray?)obj["tags"];
int tagCount = tags?.Count ?? 0;
// LINQ-to-JSON queries
var activeUsers = JArray.Parse(jsonArrayString)
.Where(u => (bool)u["is_active"]!)
.Select(u => (string?)u["user_name"])
.ToList();
// === Custom JsonConverter ===
public class BoolToIntConverter : JsonConverter<bool>
{
public override bool ReadJson(
JsonReader reader, Type objectType, bool existingValue,
bool hasExistingValue, JsonSerializer serializer)
{
return Convert.ToInt32(reader.Value) == 1;
}
public override void WriteJson(
JsonWriter writer, bool value,
JsonSerializer serializer)
{
writer.WriteValue(value ? 1 : 0);
}
}
// Usage: [JsonConverter(typeof(BoolToIntConverter))]
// public bool IsActive { get; set; }C# Records:不変データモデル
C# 9+ recordsは不変データモデルを簡潔に定義できます。Equals、GetHashCode、with式を自動生成します:
// C# Record classes for JSON deserialization (C# 9+)
using System.Text.Json.Serialization;
public record User(
[property: JsonPropertyName("user_id")] long UserId,
[property: JsonPropertyName("user_name")] string UserName,
string Email,
[property: JsonPropertyName("is_active")] bool IsActive,
decimal Balance,
List<string> Tags,
Address Address
);
public record Address(
string Street,
string City,
[property: JsonPropertyName("zip_code")] string ZipCode
);
// Deserialization works seamlessly with records
var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};
User? user = JsonSerializer.Deserialize<User>(json, options);
// Records are immutable: use "with" for modified copies
User updated = user! with { Email = "new@example.com" };
// Init-only record class (C# 10+)
public record class Product
{
public required long Id { get; init; }
public required string Name { get; init; }
public required decimal Price { get; init; }
public bool InStock { get; init; }
public List<string> Categories { get; init; } = new();
}
// Value-based equality: two records with same data are equal
var p1 = new Product { Id = 1, Name = "Keyboard", Price = 79.99m };
var p2 = new Product { Id = 1, Name = "Keyboard", Price = 79.99m };
Console.WriteLine(p1 == p2); // True手動POCO:プロパティ付きクラス
完全なコントロールが必要な場合、従来のPOCOとINotifyPropertyChangedまたはAutoMapperが最大の柔軟性を提供します:
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Text.Json.Serialization;
// POCO with INotifyPropertyChanged for WPF/MAUI data binding
public class Product : INotifyPropertyChanged
{
private long _id;
private string _name = "";
private decimal _price;
private bool _inStock;
private List<string> _categories = new();
[JsonPropertyName("product_id")]
public long Id
{
get => _id;
set => SetField(ref _id, value);
}
public string Name
{
get => _name;
set => SetField(ref _name, value);
}
public decimal Price
{
get => _price;
set => SetField(ref _price, value);
}
[JsonPropertyName("in_stock")]
public bool InStock
{
get => _inStock;
set => SetField(ref _inStock, value);
}
public List<string> Categories
{
get => _categories;
set => SetField(ref _categories, value);
}
// INotifyPropertyChanged implementation
public event PropertyChangedEventHandler? PropertyChanged;
private void OnPropertyChanged(
[CallerMemberName] string? name = null)
{
PropertyChanged?.Invoke(
this, new PropertyChangedEventArgs(name));
}
private bool SetField<T>(
ref T field, T value,
[CallerMemberName] string? name = null)
{
if (EqualityComparer<T>.Default.Equals(field, value))
return false;
field = value;
OnPropertyChanged(name);
return true;
}
// Override ToString for debugging
public override string ToString()
=> $"Product {{ Id={Id}, Name={Name}, Price={Price} }}";
}
// Usage with AutoMapper (DTO to domain model):
// var config = new MapperConfiguration(cfg =>
// cfg.CreateMap<ProductDto, Product>());
// var mapper = config.CreateMapper();
// Product product = mapper.Map<Product>(dto);ネストされたJSON構造の操作
実際のAPIは深くネストされたオブジェクトとポリモーフィック型を含みます:
ネストオブジェクト:各ネストレベルが別のC#クラスを生成します。
オブジェクト配列:"items": [{"id": 1}]はC#でList<Item>にマッピングされます。
ポリモーフィックデシリアライゼーション:.NET 7+は[JsonDerivedType]と[JsonPolymorphic]をサポートします。
// Polymorphic deserialization with .NET 7+ System.Text.Json
using System.Text.Json.Serialization;
[JsonPolymorphic(TypeDiscriminatorPropertyName = "type")]
[JsonDerivedType(typeof(EmailNotification), "email")]
[JsonDerivedType(typeof(SmsNotification), "sms")]
[JsonDerivedType(typeof(PushNotification), "push")]
public abstract class Notification
{
public string Type { get; set; } = "";
public string Message { get; set; } = "";
public DateTime CreatedAt { get; set; }
}
public class EmailNotification : Notification
{
public string Recipient { get; set; } = "";
public string Subject { get; set; } = "";
}
public class SmsNotification : Notification
{
public string PhoneNumber { get; set; } = "";
}
public class PushNotification : Notification
{
public string DeviceToken { get; set; } = "";
public string Title { get; set; } = "";
}
// JSON input:
// {"type":"email","message":"Hello","recipient":"a@b.com","subject":"Hi"}
// Automatically deserializes to EmailNotification
// Nested classes with arrays example
public class ApiResponse
{
public bool Success { get; set; }
public UserData Data { get; set; } = new();
public List<ErrorDetail> Errors { get; set; } = new();
}
public class UserData
{
public User User { get; set; } = new();
public List<Order> Orders { get; set; } = new();
public Address BillingAddress { get; set; } = new();
public Address ShippingAddress { get; set; } = new();
}
public class Order
{
public long OrderId { get; set; }
public decimal Total { get; set; }
public List<OrderItem> Items { get; set; } = new();
}
public class OrderItem
{
public long ProductId { get; set; }
public string Name { get; set; } = "";
public int Quantity { get; set; }
public decimal UnitPrice { get; set; }
}高度なパターン:ソースジェネレーター、AOT、Nullable参照型
.NET 8のSystem.Text.Jsonソースジェネレーターはコンパイル時にシリアライゼーションコードを生成し、リフレクションを排除してNative AOTデプロイメントを可能にします:
// .NET 8 Source Generator for AOT-friendly serialization
using System.Text.Json;
using System.Text.Json.Serialization;
public record Product(
[property: JsonPropertyName("product_id")] long ProductId,
string Name,
decimal Price,
[property: JsonPropertyName("in_stock")] bool InStock,
List<string> Tags,
[property: JsonPropertyName("created_at")] DateTime CreatedAt
);
// Source generator context
[JsonSerializable(typeof(Product))]
[JsonSerializable(typeof(List<Product>))]
[JsonSourceGenerationOptions(
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
GenerationMode = JsonSourceGenerationMode.Default)]
public partial class AppJsonContext : JsonSerializerContext { }
// Zero-reflection serialization (AOT-compatible)
var product = JsonSerializer.Deserialize(
json, AppJsonContext.Default.Product);
var jsonOut = JsonSerializer.Serialize(
product, AppJsonContext.Default.Product);
// Works with ASP.NET Core minimal APIs
var builder = WebApplication.CreateBuilder(args);
builder.Services.ConfigureHttpJsonOptions(options =>
{
options.SerializerOptions.TypeInfoResolverChain
.Insert(0, AppJsonContext.Default);
});C# 8+のNullable参照型はコンパイル時のnull安全を提供します。C# 11+のrequiredプロパティと組み合わせて使用:
// Nullable reference types + required properties (C# 11+)
#nullable enable
public class UserProfile
{
public required string Name { get; init; }
public required string Email { get; init; }
public string? Nickname { get; init; } // optional
public int Age { get; init; }
public string? AvatarUrl { get; init; } // optional
public required List<string> Roles { get; init; }
}
// Deserialization enforces required properties
var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};
var user = JsonSerializer.Deserialize<UserProfile>(json, options)
?? throw new InvalidOperationException(
"Failed to deserialize user profile");
// Compiler warning if you forget to set required properties:
// var profile = new UserProfile { Name = "Alice" };
// Error CS9035: Required member 'Email' must be set
// JsonRequired attribute for runtime enforcement
public class StrictModel
{
[JsonRequired]
public string Id { get; set; } = "";
[JsonRequired]
public string Name { get; set; } = "";
public string? Description { get; set; }
}System.Text.Json vs Newtonsoft:System.Text.Jsonは2-5倍高速で、メモリ使用量が少なく、ソースジェネレーターをサポート。Newtonsoftはより多くの機能を提供します。
JSON to C#変換のベストプラクティス
堅牢な.NETアプリケーションを構築するためのベストプラクティス:
PascalCaseプロパティと属性:[JsonPropertyName]でJSONキーをマッピング。
Nullable型を有効化:#nullable enableでコンパイル時のnull安全。
未知のプロパティを処理:System.Text.Jsonはデフォルトで無視。NewtonsoftはMissingMemberHandling.Ignoreを設定。
金額にはdecimal:金額にfloatやdoubleを使用しない。
DTOにはrecordsを優先:init-onlyプロパティ付きrecordsで不変性を実現。
パフォーマンスにはソースジェネレーター:.NET 8+で[JsonSerializable]。
デシリアライズデータを検証:データアノテーションまたはFluentValidation。
関連ツール:JSON to Java、JSON to TypeScript、JSON to Kotlin。
JSON to JavaJSON to TypeScriptJSON to Kotlin
よくある質問
System.Text.JsonとNewtonsoft:どちらを使うべき?
新しい.NET 8+プロジェクトにはSystem.Text.Jsonが推奨です。フレームワーク組み込みで、2-5倍高速、AOTソースジェネレーターをサポート。Newtonsoftは既存プロジェクトやJObjectが必要な複雑なシナリオに有用です。
C# Recordsか従来のクラスか?
不変DTOにはRecords(C# 9+)を使用。可変性やINotifyPropertyChangedが必要な場合はクラス。ASP.NET CoreではRecordsがモダンなベストプラクティスです。
未知のJSONプロパティをどう処理する?
System.Text.Jsonはデフォルトで無視します。キャプチャするには[JsonExtensionData]を使用。Newtonsoftはデフォルトで例外を投げるので、MissingMemberHandling.Ignoreを設定してください。
JSONからC#クラスへの変換はすべての.NET開発者の基本スキルです。無料オンラインツールで即座にコードを生成してください。