ファイル

【C#】System.Text.JsonとNewtonsoft.JsonでJSON作成・整形・カスタム変換を極める

C#でJSONを作成するなら標準のSystem.Text.Jsonが高速で軽く、JsonSerializer.Serialize(object)だけで手軽に文字列化でき、WriteIndentedで整形も可能です。

高度な変換や古い環境では機能が豊富なNewtonsoft.Jsonが便利で、JsonConvert.SerializeObjectを使い同様に生成できます。

属性でキー名変更やカスタムコンバーターで独自フォーマットも扱え、目的と環境に応じ選択するのが得策です。

目次から探す
  1. JSON作成のアプローチ概要
  2. System.Text.Jsonの使い方
  3. Newtonsoft.Jsonの使い方
  4. ライブラリ比較と選定ポイント
  5. 実践的シリアライズシナリオ
  6. 落とし穴と対策
  7. セキュリティと安定性
  8. パフォーマンス向上のヒント
  9. まとめ

JSON作成のアプローチ概要

C#でJSONを作成する際には、主にSystem.Text.JsonNewtonsoft.Json(Json.NET)がよく使われています。

どちらのライブラリもJSONのシリアル化・逆シリアル化をサポートしていますが、プロジェクトの要件や環境によって適切な選択が必要です。

ここでは、JSON作成に使うライブラリを選ぶ際の重要なチェックポイントを解説いたします。

ライブラリ選択のチェックポイント

速度とメモリ消費

JSONのシリアル化や逆シリアル化は、アプリケーションのパフォーマンスに大きく影響します。

特に大量のデータを扱う場合やリアルタイム処理が求められる場合は、速度とメモリ消費のバランスが重要です。

  • System.Text.Json

Microsoftが.NET Core 3.0以降で提供している標準ライブラリで、パフォーマンスに優れています。

内部的にSpan<T>やUtf8JsonReader/Writerを活用し、メモリ割り当てを最小限に抑えています。

例えば、JSONの読み書きにおいて高速で、GC(ガベージコレクション)発生を抑制する設計がなされています。

ただし、機能面でNewtonsoft.Jsonに比べてまだ一部不足している部分もあります。

  • Newtonsoft.Json

長年にわたり広く使われてきたライブラリで、機能が非常に豊富です。

ただし、内部で文字列操作やリフレクションを多用するため、System.Text.Jsonに比べるとややメモリ消費が多く、処理速度も劣る傾向があります。

とはいえ、最適化やキャッシュを活用すれば十分なパフォーマンスを発揮します。

ライブラリシリアル化速度メモリ消費備考
System.Text.Json高速低い.NET標準、軽量設計
Newtonsoft.Json中程度やや多い機能豊富、互換性高

機能の充実度

JSONの作成や解析において、どのような機能が必要かも選定の重要なポイントです。

以下のような機能の有無を確認しましょう。

  • 属性による細かい制御

どちらのライブラリも属性でプロパティ名の変更や無視設定が可能ですが、Newtonsoft.Jsonはより多彩な属性が用意されています。

例:JsonPropertyで名前変更、JsonIgnoreで除外、JsonConverterでカスタム変換など。

  • カスタムコンバーターの柔軟性

独自の型変換を行うカスタムコンバーターは両者でサポートされていますが、Newtonsoft.Jsonはより複雑なシナリオに対応しやすい設計です。

  • 動的JSON操作

Newtonsoft.JsonはJObjectJTokenを使った動的なJSON操作が可能で、構造が不明なJSONの処理に便利です。

System.Text.JsonもJsonDocumentJsonElementで読み取りはできますが、書き換えや動的操作は制限があります。

  • シリアル化設定の柔軟性

例えば、循環参照の処理、Null値の扱い、日付フォーマットのカスタマイズなど、Newtonsoft.Jsonは細かい設定が可能です。

System.Text.Jsonも徐々に機能が拡充されていますが、まだNewtonsoft.Jsonに及ばない部分があります。

機能項目System.Text.JsonNewtonsoft.Json
属性によるプロパティ制御ありあり
カスタムコンバーターありあり
動的JSON操作制限あり充実
循環参照対応制限ありあり
日付・Enumフォーマット基本対応豊富

依存関係とライセンス

ライブラリの依存関係やライセンスも選択時に考慮すべきポイントです。

  • System.Text.Json

.NETの標準ライブラリとして組み込まれているため、追加の依存関係は不要です。

ライセンスは.NETのオープンソースライセンス(MITライセンス)で、商用利用も問題ありません。

  • Newtonsoft.Json

NuGetパッケージとして提供されており、プロジェクトに追加する必要があります。

依存関係は少なく、ほぼ単独で動作します。

ライセンスはMITライセンスで、こちらも商用利用に制限はありません。

項目System.Text.JsonNewtonsoft.Json
依存関係.NET標準組み込みNuGetパッケージ追加必要
ライセンスMITMIT
商用利用問題なし問題なし

以上のように、速度やメモリ消費、機能の充実度、依存関係やライセンスの観点からライブラリを選ぶことが重要です。

プロジェクトの規模や要件に応じて、最適なライブラリを選択してください。

System.Text.Jsonの使い方

基本シリアル化フロー

System.Text.JsonでJSONを作成する基本的な流れは、JsonSerializer.Serializeメソッドを使ってC#のオブジェクトをJSON文字列に変換することです。

以下のサンプルコードは、シンプルなクラスPersonのインスタンスをJSONにシリアル化しています。

using System;
using System.Text.Json;
public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}
public class Program
{
    public static void Main()
    {
        var person = new Person
        {
            Name = "Alice",
            Age = 28
        };
        string jsonString = JsonSerializer.Serialize(person);
        Console.WriteLine(jsonString);
    }
}
{"Name":"Alice","Age":28}

このように、Serializeメソッドにオブジェクトを渡すだけでJSON文字列が生成されます。

逆に、JsonSerializer.Deserialize<T>を使うとJSON文字列からオブジェクトに変換できます。

フォーマットオプション

WriteIndentedによる整形

デフォルトでは、System.Text.JsonはコンパクトなJSONを生成しますが、JsonSerializerOptionsWriteIndentedプロパティをtrueに設定すると、インデント付きの整形済みJSONを出力できます。

var options = new JsonSerializerOptions
{
    WriteIndented = true
};
string jsonString = JsonSerializer.Serialize(person, options);
Console.WriteLine(jsonString);
{
  "Name": "Alice",
  "Age": 28
}

この設定は、ログ出力や人間が読みやすいJSONを生成したい場合に便利です。

Encoder設定と言語別エスケープ

JsonSerializerOptionsEncoderプロパティを使うと、JSON文字列内のエスケープ処理をカスタマイズできます。

例えば、HTMLタグや特定のUnicode文字をエスケープすることでXSS対策が可能です。

using System.Text.Encodings.Web;
using System.Text.Unicode;
var options = new JsonSerializerOptions
{
    Encoder = JavaScriptEncoder.Create(UnicodeRanges.BasicLatin, UnicodeRanges.CjkUnifiedIdeographs),
    WriteIndented = true
};
var data = new { Text = "<script>alert(\"XSS\")</script>あいう" };
string jsonString = JsonSerializer.Serialize(data, options);
Console.WriteLine(jsonString);
{
  "Text": "\u003cscript\u003ealert(\"XSS\")\u003c/script\u003eあいう"
}

この例では、HTMLの<>がUnicodeエスケープされており、CJK(漢字・ひらがな・カタカナ)はそのまま出力されています。

JsonSerializerOptionsの活用

IgnoreNullValuesとDefaultIgnoreCondition

IgnoreNullValuesは.NET 5.0まで使われていたプロパティで、nullのプロパティをJSONに含めない設定です。

現在はDefaultIgnoreConditionに置き換えられています。

var options = new JsonSerializerOptions
{
    DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull,
    WriteIndented = true
};
var person = new Person
{
    Name = "Bob",
    Age = 0 // 0はnullではないため出力される
};
string jsonString = JsonSerializer.Serialize(person, options);
Console.WriteLine(jsonString);
{
  "Name": "Bob",
  "Age": 0
}

DefaultIgnoreConditionWhenWritingNullのほかにNever(常に書き込む)、WhenWritingDefault(デフォルト値を無視)などが指定可能です。

PropertyNamingPolicyとDictionaryKeyPolicy

JSONのキー名を変換するために、PropertyNamingPolicyDictionaryKeyPolicyを設定できます。

例えば、C#のPascalCaseのプロパティ名をcamelCaseに変換したい場合は以下のようにします。

var options = new JsonSerializerOptions
{
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
    DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
    WriteIndented = true
};
var person = new Person
{
    Name = "Charlie",
    Age = 35
};
string jsonString = JsonSerializer.Serialize(person, options);
Console.WriteLine(jsonString);
{
  "name": "Charlie",
  "age": 35
}

PropertyNamingPolicyはクラスのプロパティ名に、DictionaryKeyPolicyは辞書のキーに適用されます。

属性ベースの設定

JsonPropertyNameでキー名変更

プロパティ名とJSONのキー名を個別に指定したい場合は、[JsonPropertyName]属性を使います。

using System.Text.Json.Serialization;
public class Person
{
    [JsonPropertyName("full_name")]
    public string Name { get; set; }
    [JsonPropertyName("years_old")]
    public int Age { get; set; }
}
public class Program
{
    public static void Main()
    {
        var person = new Person { Name = "Diana", Age = 40 };
        var options = new JsonSerializerOptions { WriteIndented = true };
        string jsonString = JsonSerializer.Serialize(person, options);
        Console.WriteLine(jsonString);
    }
}
{
  "full_name": "Diana",
  "years_old": 40
}

このように、JSONのキー名を自由にカスタマイズできます。

JsonIgnoreで出力除外

特定のプロパティをJSONに含めたくない場合は、[JsonIgnore]属性を付けます。

public class Person
{
    public string Name { get; set; }
    [JsonIgnore]
    public int Age { get; set; }
}

この場合、Ageはシリアル化されません。

JsonIncludeで非publicプロパティ公開

System.Text.Jsonはデフォルトでpublicなプロパティのみシリアル化しますが、[JsonInclude]属性を使うとprivateやinternalのプロパティやフィールドも含められます。

public class Person
{
    [JsonInclude]
    public int Id { get; private set; }
    public string Name { get; set; }
    public Person(int id)
    {
        Id = id;
    }
}

この例では、Idはprivate setterですがJSONに含まれます。

カスタムコンバーター作成手順

JsonConverter<T>の実装ポイント

独自の型や特殊な変換が必要な場合は、JsonConverter<T>を継承してカスタムコンバーターを作成します。

以下はDateTimeを特定フォーマットでシリアル化・逆シリアル化する例です。

using System;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Globalization;
public class DateTimeConverter : JsonConverter<DateTime>
{
    private readonly string _format;
    public DateTimeConverter(string format)
    {
        _format = format;
    }
    public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        string dateString = reader.GetString();
        return DateTime.ParseExact(dateString, _format, CultureInfo.InvariantCulture);
    }
    public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
    {
        writer.WriteStringValue(value.ToString(_format));
    }
}

オプションへの登録方法

作成したコンバーターはJsonSerializerOptions.Convertersに追加して使います。

var options = new JsonSerializerOptions();
options.Converters.Add(new DateTimeConverter("yyyy-MM-dd"));
var obj = new { Date = new DateTime(2023, 6, 1) };
string jsonString = JsonSerializer.Serialize(obj, options);
Console.WriteLine(jsonString);
{"Date":"2023-06-01"}

Utf8JsonWriterの低レベル操作

バイナリSpanと組み合わせた高速書き込み

Utf8JsonWriterは低レベルのJSON書き込みAPIで、バッファに直接書き込むため高速です。

Span<byte>Memory<byte>と組み合わせて効率的にJSONを生成できます。

using System;
using System.Buffers;
using System.Text.Json;
public class Program
{
    public static void Main()
    {
        var buffer = new ArrayBufferWriter<byte>();
        using (var writer = new Utf8JsonWriter(buffer, new JsonWriterOptions { Indented = true }))
        {
            writer.WriteStartObject();
            writer.WriteString("message", "Hello, Utf8JsonWriter!");
            writer.WriteNumber("year", 2024);
            writer.WriteEndObject();
            writer.Flush();
        }
        string jsonString = System.Text.Encoding.UTF8.GetString(buffer.WrittenSpan);
        Console.WriteLine(jsonString);
    }
}
{
  "message": "Hello, Utf8JsonWriter!",
  "year": 2024
}

Flush制御とバッファ管理

Utf8JsonWriterFlushメソッドでバッファの内容を確定させます。

大きなJSONを分割して書き込む場合やストリームに直接書き込む際に重要です。

バッファの再利用やArrayPool<byte>と組み合わせることでメモリ効率を高められます。

JsonDocumentでの解析と再生成

LINQライクな要素走査

JsonDocumentは読み取り専用のJSON DOMで、JSON文字列を解析して要素を走査できます。

LINQのようにネストした要素を簡単に取得可能です。

using System;
using System.Text.Json;
public class Program
{
    public static void Main()
    {
        string json = "{\"Name\":\"Eve\",\"Scores\":[100, 95, 88]}";
        using var doc = JsonDocument.Parse(json);
        var root = doc.RootElement;
        string name = root.GetProperty("Name").GetString();
        var scores = root.GetProperty("Scores").EnumerateArray();
        Console.WriteLine($"Name: {name}");
        Console.Write("Scores: ");
        foreach (var score in scores)
        {
            Console.Write($"{score.GetInt32()} ");
        }
    }
}
Name: Eve
Scores: 100 95 88

局所的な置換と部分更新

JsonDocumentは読み取り専用なので直接書き換えはできませんが、必要な部分だけを取り出して新しいJSONを作成することが可能です。

例えば、特定のプロパティを変更して再シリアル化する場合は、Utf8JsonWriterなどと組み合わせて処理します。

ソースジェネレーターによる高速化

AddJsonSerializableAttributeの使い方

.NET 6以降では、System.Text.Jsonのソースジェネレーター機能を使い、コンパイル時にシリアル化コードを生成して高速化できます。

対象の型に[JsonSerializable(typeof(YourType))]属性を付け、JsonSerializerContextを継承したクラスを作成します。

using System.Text.Json.Serialization;
[JsonSerializable(typeof(Person))]
public partial class PersonJsonContext : JsonSerializerContext
{
}

シリアル化は以下のように行います。

string jsonString = JsonSerializer.Serialize(person, PersonJsonContext.Default.Person);

生成コードの確認とデバッグ

生成されたコードはビルド時に自動生成され、ILコードの最適化やリフレクションの回避により高速化されます。

Visual Studioの「オブジェクトブラウザー」や「デコンパイラー」で生成コードを確認可能です。

エラーと例外処理

JsonExceptionの主な発生パターン

System.Text.Jsonのシリアル化・逆シリアル化で発生する例外は主にJsonExceptionです。

主な原因は以下の通りです。

  • JSONの形式が不正(構文エラー)
  • 型の不一致(例えば文字列を数値に変換しようとした)
  • 必須プロパティの欠落
  • カスタムコンバーター内の例外

読み取りオプションでの緩和策

JsonSerializerOptionsAllowTrailingCommasReadCommentHandlingを設定すると、JSONの末尾のカンマやコメントを許容して柔軟に読み取れます。

var options = new JsonSerializerOptions
{
    AllowTrailingCommas = true,
    ReadCommentHandling = JsonCommentHandling.Skip
};
string json = "{ \"Name\": \"Frank\", } // コメント";
var person = JsonSerializer.Deserialize<Person>(json, options);

これにより、多少フォーマットが厳密でないJSONでも例外を回避できます。

Newtonsoft.Jsonの使い方

基本シリアル化フロー

Newtonsoft.Json(Json.NET)でJSONを作成する基本は、JsonConvert.SerializeObjectメソッドを使ってC#のオブジェクトをJSON文字列に変換することです。

以下はシンプルなPersonクラスのインスタンスをシリアル化する例です。

using System;
using Newtonsoft.Json;
public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}
public class Program
{
    public static void Main()
    {
        var person = new Person
        {
            Name = "Alice",
            Age = 28
        };
        string jsonString = JsonConvert.SerializeObject(person);
        Console.WriteLine(jsonString);
    }
}
{"Name":"Alice","Age":28}

JsonConvert.DeserializeObject<T>を使うと、JSON文字列からオブジェクトに変換できます。

FormattingとJsonSerializerSettings

JsonConvert.SerializeObjectは第2引数にFormattingJsonSerializerSettingsを指定して、出力の細かい制御が可能です。

NullValueHandling

NullValueHandlingは、nullのプロパティをJSONに含めるかどうかを制御します。

var person = new Person
{
    Name = "Bob",
    Age = 0,
    // 例えばAddressがnullの場合
    Address = null
};
var settings = new JsonSerializerSettings
{
    NullValueHandling = NullValueHandling.Ignore,
    Formatting = Formatting.Indented
};
string jsonString = JsonConvert.SerializeObject(person, settings);
Console.WriteLine(jsonString);
{
  "Name": "Bob",
  "Age": 0
}

AddressnullのためJSONに含まれていません。

DefaultValueHandling

DefaultValueHandlingは、プロパティのデフォルト値(例えばintの0やboolのfalse)をJSONに含めるか制御します。

var settings = new JsonSerializerSettings
{
    DefaultValueHandling = DefaultValueHandling.Ignore,
    Formatting = Formatting.Indented
};
var person = new Person
{
    Name = "Carol",
    Age = 0 // デフォルト値なので無視される
};
string jsonString = JsonConvert.SerializeObject(person, settings);
Console.WriteLine(jsonString);
{
  "Name": "Carol"
}

Ageが0のため省略されています。

ReferenceLoopHandling

循環参照があるオブジェクトをシリアル化すると例外が発生します。

ReferenceLoopHandlingで回避方法を指定できます。

var settings = new JsonSerializerSettings
{
    ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
    Formatting = Formatting.Indented
};
var parent = new Person { Name = "Parent" };
var child = new Person { Name = "Child" };
parent.Child = child;
child.Parent = parent; // 循環参照
string jsonString = JsonConvert.SerializeObject(parent, settings);
Console.WriteLine(jsonString);
{
  "Name": "Parent",
  "Child": {
    "Name": "Child"
  }
}

ParentChildParentプロパティは無視され、例外を回避しています。

属性ベースの設定

JsonPropertyでキー名変更

[JsonProperty]属性を使うと、JSONのキー名を自由に変更できます。

using Newtonsoft.Json;
public class Person
{
    [JsonProperty("full_name")]
    public string Name { get; set; }
    [JsonProperty("years_old")]
    public int Age { get; set; }
}

シリアル化すると以下のようになります。

{
  "full_name": "Dave",
  "years_old": 45
}

JsonIgnoreで出力除外

[JsonIgnore]属性を付けると、そのプロパティはシリアル化・逆シリアル化の対象から除外されます。

public class Person
{
    public string Name { get; set; }
    [JsonIgnore]
    public int Age { get; set; }
}

AgeはJSONに含まれません。

JsonConverterAttributeで独自変換

特定のプロパティにカスタムコンバーターを適用したい場合は、[JsonConverter]属性を使います。

public class Person
{
    public string Name { get; set; }
    [JsonConverter(typeof(CustomDateTimeConverter))]
    public DateTime BirthDate { get; set; }
}

このように属性で指定すると、そのプロパティだけに独自の変換ロジックを適用できます。

カスタムコンバーター作成手順

JsonConverter継承とCanConvert実装

カスタムコンバーターはJsonConverterを継承し、CanConvertメソッドで対象型を指定します。

以下はDateTimeを特定フォーマットで処理する例です。

using Newtonsoft.Json;
using System;
public class CustomDateTimeConverter : JsonConverter
{
    private readonly string _format = "yyyy-MM-dd";
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(DateTime);
    }
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var date = (DateTime)value;
        writer.WriteValue(date.ToString(_format));
    }
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var dateStr = (string)reader.Value;
        return DateTime.ParseExact(dateStr, _format, null);
    }
}

グローバル登録と局所登録の違い

  • グローバル登録

JsonSerializerSettings.Convertersに追加すると、すべてのシリアル化・逆シリアル化で適用されます。

var settings = new JsonSerializerSettings();
settings.Converters.Add(new CustomDateTimeConverter());
  • 局所登録

プロパティに[JsonConverter]属性を付けると、そのプロパティだけに適用されます。

ContractResolverによる細粒度制御

DefaultContractResolver

デフォルトのDefaultContractResolverは、プロパティ名をそのままJSONキーに使います。

カスタマイズのベースとして使われます。

CamelCasePropertyNamesContractResolver

CamelCasePropertyNamesContractResolverを使うと、C#のPascalCaseのプロパティ名をcamelCaseに変換してJSONに出力します。

var settings = new JsonSerializerSettings
{
    ContractResolver = new CamelCasePropertyNamesContractResolver(),
    Formatting = Formatting.Indented
};
var person = new Person { Name = "Ellen", Age = 30 };
string jsonString = JsonConvert.SerializeObject(person, settings);
Console.WriteLine(jsonString);
{
  "name": "Ellen",
  "age": 30
}

カスタムResolverの構築

DefaultContractResolverを継承して、プロパティのシリアル化条件や名前変換を独自に制御できます。

using Newtonsoft.Json.Serialization;
public class CustomContractResolver : DefaultContractResolver
{
    protected override string ResolvePropertyName(string propertyName)
    {
        return "prefix_" + propertyName.ToLower();
    }
}

JToken/JObjectを用いた動的操作

要素の追加・削除・置換

JObjectは動的にJSONオブジェクトを操作できます。

以下は要素の追加例です。

using Newtonsoft.Json.Linq;
var obj = JObject.Parse("{\"Name\":\"Frank\"}");
obj["Age"] = 40; // 追加
obj.Remove("Name"); // 削除
obj["City"] = "Tokyo"; // 追加
Console.WriteLine(obj.ToString());
{
  "Age": 40,
  "City": "Tokyo"
}

JSONPathによるクエリ

SelectTokenメソッドでJSONPathを使い、特定の要素を抽出できます。

var json = @"{
  'People': [
    { 'Name': 'Gina', 'Age': 25 },
    { 'Name': 'Hank', 'Age': 30 }
  ]
}";
var jObj = JObject.Parse(json);
var person = jObj.SelectToken("$.People[?(@.Name == 'Hank')]");
Console.WriteLine(person.ToString());
{
  "Name": "Hank",
  "Age": 30
}

日付・Enum・数値フォーマット

IsoDateTimeConverter

IsoDateTimeConverterを使うと、ISO 8601形式で日付をシリアル化できます。

var settings = new JsonSerializerSettings
{
    Converters = { new IsoDateTimeConverter() },
    Formatting = Formatting.Indented
};

StringEnumConverter

StringEnumConverterを使うと、Enum値を文字列としてJSONに出力できます。

using Newtonsoft.Json.Converters;
var settings = new JsonSerializerSettings
{
    Converters = { new StringEnumConverter() },
    Formatting = Formatting.Indented
};

CustomCreationConverterで複雑型生成

CustomCreationConverter<T>を継承すると、逆シリアル化時に複雑な初期化処理を行えます。

エラーと例外処理

ErrorEventHandlerでの復旧

JsonSerializerSettings.Errorイベントにハンドラーを登録すると、シリアル化・逆シリアル化中のエラーを捕捉し、処理を継続できます。

var settings = new JsonSerializerSettings();
settings.Error += (sender, args) =>
{
    Console.WriteLine($"Error: {args.ErrorContext.Error.Message}");
    args.ErrorContext.Handled = true; // エラーを無視して続行
};

ErrorContextを利用したスキップ

ErrorContextHandledプロパティをtrueに設定すると、エラーが発生したプロパティをスキップして処理を続けられます。

TypeNameHandlingの注意点

型情報混入によるリスク

TypeNameHandlingを有効にすると、JSONに型情報$typeが埋め込まれます。

これにより、逆シリアル化時に任意の型を生成できるため、悪意あるJSONでコード実行のリスクが生じます。

安全な設定例

安全に使うには、SerializationBinderを設定して許可する型を限定するか、TypeNameHandlingを必要最低限に抑えます。

var settings = new JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.Objects,
    SerializationBinder = new KnownTypesBinder()
};

KnownTypesBinderは許可する型を明示的に管理するクラスです。

ライブラリ比較と選定ポイント

パフォーマンスベンチマーク

シリアル化速度の実測値

System.Text.JsonNewtonsoft.Jsonのシリアル化速度は、多くのベンチマークで比較されています。

一般的に、System.Text.Jsonは.NET標準ライブラリとして最適化されており、特に.NET Core 3.0以降の環境で高速なシリアル化を実現しています。

例えば、同じ大きさのオブジェクトをシリアル化した場合、System.Text.JsonNewtonsoft.Jsonよりも約2倍程度高速に処理できるケースが多いです。

これは、System.Text.JsonSpan<T>Utf8JsonWriterなどの低レベルAPIを活用し、メモリ割り当てを抑制しているためです。

ただし、複雑なカスタムコンバーターや動的なJSON操作を多用する場合は、Newtonsoft.Jsonの方が最適化されているケースもあります。

シンプルなPOCOのシリアル化ではSystem.Text.Jsonが優位ですが、機能の多様性が必要な場合は速度差が縮まることもあります。

メモリ割り当て量の比較

メモリ割り当ての観点でもSystem.Text.Jsonは優れています。

Newtonsoft.Jsonは内部で多くの文字列操作やリフレクションを行うため、ガベージコレクションの負荷が高くなる傾向があります。

一方、System.Text.Jsonはバッファの再利用やSpan<T>を活用し、不要なメモリ割り当てを減らしています。

これにより、大量のJSONデータを扱う場合やリアルタイム処理でGCの影響を抑えたい場合に有利です。

ライブラリシリアル化速度メモリ割り当て量備考
System.Text.Json高速低い.NET標準、低レベルAPI活用
Newtonsoft.Json中程度多い機能豊富だが割り当て多め

機能対比表

属性機能の網羅性

機能項目System.Text.JsonNewtonsoft.Json
プロパティ名変更属性[JsonPropertyName][JsonProperty]
プロパティ無視属性[JsonIgnore][JsonIgnore]
非publicプロパティのシリアル化[JsonInclude]なし(カスタムで可能)
カスタムコンバーター属性ありあり
Null値無視設定DefaultIgnoreConditionNullValueHandling
デフォルト値無視設定ありDefaultValueHandling
循環参照制御制限ありあり

Newtonsoft.Jsonは長年の実績から多彩な属性が揃っており、細かい制御が可能です。

System.Text.Jsonは基本的な属性は揃っていますが、まだ一部機能が限定的です。

動的生成APIの有無

機能項目System.Text.JsonNewtonsoft.Json
動的JSON操作JsonDocument(読み取り専用)JObject/JToken(読み書き可能)
JSONPathサポートなしあり
動的オブジェクト生成制限あり充実

動的にJSONを操作したい場合は、Newtonsoft.Jsonの方が柔軟で使いやすいです。

System.Text.Jsonは読み取り専用のAPIが中心で、動的編集は難しいです。

移行と併用の戦略

NewtonsoftからSystem.Text.Jsonへの手順

  1. 依存関係の整理

既存プロジェクトからNewtonsoft.Jsonの参照を確認し、System.Text.Jsonを利用可能な環境(.NET Core 3.0以降)にアップデートします。

  1. シリアル化コードの置換

JsonConvert.SerializeObjectDeserializeObjectJsonSerializer.SerializeDeserializeに置き換えます。

オプションや属性の違いに注意しながら、JsonSerializerOptionsを適切に設定します。

  1. カスタムコンバーターの移植

Newtonsoft.JsonのカスタムコンバーターはJsonConverter<T>に書き換えが必要です。

APIの違いを理解して実装します。

  1. テストと検証

JSONの出力形式や動作が変わっていないか、単体テストや統合テストで確認します。

既存コードへの影響ポイント

  • 属性の違い

Newtonsoft.Json[JsonProperty]System.Text.Json[JsonPropertyName]に置き換えが必要です。

一部の属性は存在しないため、コード修正が必要です。

  • 動的JSON操作の制限

JObjectJTokenを多用している場合、System.Text.Jsonでは同様の操作が難しいため、コードの大幅な変更が必要です。

  • 循環参照の扱い

System.Text.Jsonは循環参照のサポートが限定的なので、設計見直しや回避策が必要になることがあります。

併用時の競合回避テクニック

  • 名前空間の明示的指定

両ライブラリのクラス名が似ているため、usingディレクティブで名前空間を明示的に指定し、混乱を避けます。

  • 用途ごとに使い分け

例えば、APIのレスポンスはSystem.Text.Jsonで処理し、動的JSON操作や複雑な変換はNewtonsoft.Jsonで行うなど、役割を分けます。

  • ラッパークラスの作成

JSON処理を抽象化したラッパークラスを作り、内部でどちらのライブラリを使うか切り替えられる設計にすると、将来的な移行が容易になります。

これらのポイントを踏まえ、プロジェクトの要件や既存コードの状況に応じて最適な選択と移行計画を立てることが重要です。

実践的シリアライズシナリオ

シンプルなPOCOのシリアライズ

POCO(Plain Old CLR Object)は、単純なクラスでプロパティのみを持つオブジェクトのことです。

System.Text.JsonNewtonsoft.Jsonを使って簡単にシリアライズできます。

using System;
using System.Text.Json;
public class Product
{
    public string Name { get; set; }
    public decimal Price { get; set; }
}
public class Program
{
    public static void Main()
    {
        var product = new Product
        {
            Name = "Laptop",
            Price = 1299.99m
        };
        string json = JsonSerializer.Serialize(product, new JsonSerializerOptions { WriteIndented = true });
        Console.WriteLine(json);
    }
}
{
  "Name": "Laptop",
  "Price": 1299.99
}

このように、単純なクラスはそのままシリアライズ可能で、WriteIndentedオプションで見やすく整形できます。

Dictionaryと匿名型の扱い

辞書型や匿名型もJSONにシリアライズできます。

辞書はキーと値のペアをJSONオブジェクトとして表現し、匿名型はプロパティ名をキーにしてシリアライズされます。

using System;
using System.Collections.Generic;
using System.Text.Json;
public class Program
{
    public static void Main()
    {
        var dict = new Dictionary<string, int>
        {
            ["apple"] = 3,
            ["banana"] = 5
        };
        string dictJson = JsonSerializer.Serialize(dict, new JsonSerializerOptions { WriteIndented = true });
        Console.WriteLine(dictJson);
        var anon = new { City = "Tokyo", Population = 14000000 };
        string anonJson = JsonSerializer.Serialize(anon, new JsonSerializerOptions { WriteIndented = true });
        Console.WriteLine(anonJson);
    }
}
{
  "apple": 3,
  "banana": 5
}
{
  "City": "Tokyo",
  "Population": 14000000
}

辞書のキーは文字列である必要があり、匿名型は型名がないためシンプルにJSON化されます。

コレクションとネスト構造

リストや配列などのコレクションはJSONの配列としてシリアライズされます。

ネストしたオブジェクトもそのまま階層構造で表現されます。

using System;
using System.Collections.Generic;
using System.Text.Json;
public class Order
{
    public int OrderId { get; set; }
    public List<Product> Products { get; set; }
}
public class Product
{
    public string Name { get; set; }
    public decimal Price { get; set; }
}
public class Program
{
    public static void Main()
    {
        var order = new Order
        {
            OrderId = 1001,
            Products = new List<Product>
            {
                new Product { Name = "Mouse", Price = 25.5m },
                new Product { Name = "Keyboard", Price = 45.0m }
            }
        };
        string json = JsonSerializer.Serialize(order, new JsonSerializerOptions { WriteIndented = true });
        Console.WriteLine(json);
    }
}
{
  "OrderId": 1001,
  "Products": [
    {
      "Name": "Mouse",
      "Price": 25.5
    },
    {
      "Name": "Keyboard",
      "Price": 45.0
    }
  ]
}

ネスト構造はJSONの階層として自然に表現され、複雑なデータも扱いやすいです。

ストリームを使ったI/O

ファイル書き込み

JSONをファイルに書き込む場合は、FileStreamStreamWriterと組み合わせてシリアライズします。

using System;
using System.IO;
using System.Text.Json;
public class Program
{
    public static void Main()
    {
        var data = new { Name = "FileTest", Value = 123 };
        using (var stream = new FileStream("output.json", FileMode.Create))
        {
            JsonSerializer.Serialize(stream, data, new JsonSerializerOptions { WriteIndented = true });
        }
        Console.WriteLine("JSONファイルに書き込み完了");
    }
}

このコードはoutput.jsonファイルに整形済みJSONを書き込みます。

ネットワーク送信

ネットワーク通信でJSONを送信する場合は、HttpClientStringContentにJSON文字列をセットして送信します。

using System;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
public class Program
{
    public static async Task Main()
    {
        var client = new HttpClient();
        var data = new { User = "network", Score = 99 };
        string json = JsonSerializer.Serialize(data);
        var content = new StringContent(json, Encoding.UTF8, "application/json");
        var response = await client.PostAsync("https://example.com/api/score", content);
        Console.WriteLine($"レスポンスステータス: {response.StatusCode}");
    }
}

JSON文字列をHTTPリクエストのボディにセットして送信します。

JSONとWeb API連携

ASP.NET Core既定の動作

ASP.NET CoreはデフォルトでSystem.Text.Jsonを使ってリクエストボディのJSONをモデルにバインドし、レスポンスをJSONで返します。

コントローラーのアクションでPOCOを返すだけで自動的にシリアライズされます。

[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    [HttpGet("{id}")]
    public ActionResult<Product> GetProduct(int id)
    {
        var product = new Product { Name = "Sample", Price = 100 };
        return Ok(product);
    }
}

この場合、ProductオブジェクトはJSONに変換されてクライアントに返されます。

カスタムフォーマッタ挿入

既定のJSONシリアライザーをカスタマイズしたい場合は、Startup.csAddControllersJsonOptionsを設定します。

services.AddControllers()
    .AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.WriteIndented = true;
        options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
    });

これにより、API全体のJSON出力がインデント付きかつcamelCaseになります。

設定ファイル活用

既存JSONのマージ更新

設定ファイルなど既存のJSONに新しい値を追加・更新したい場合は、一度JsonDocumentJObjectで読み込み、必要な部分を変更してから再シリアライズします。

using System;
using System.IO;
using System.Text.Json;
public class Program
{
    public static void Main()
    {
        string json = File.ReadAllText("config.json");
        using var doc = JsonDocument.Parse(json);
        var root = doc.RootElement.Clone();
        using var stream = new MemoryStream();
        using (var writer = new Utf8JsonWriter(stream, new JsonWriterOptions { Indented = true }))
        {
            writer.WriteStartObject();
            foreach (var property in root.EnumerateObject())
            {
                if (property.NameEquals("Setting1"))
                {
                    writer.WriteString("Setting1", "UpdatedValue");
                }
                else
                {
                    property.WriteTo(writer);
                }
            }
            writer.WriteEndObject();
        }
        string updatedJson = System.Text.Encoding.UTF8.GetString(stream.ToArray());
        File.WriteAllText("config.json", updatedJson);
        Console.WriteLine("設定ファイルを更新しました");
    }
}

コメント除去と再フォーマット

System.Text.Jsonはコメントをサポートしませんが、JsonDocumentJsonReaderOptionsでコメントをスキップして読み込み可能です。

読み込んだJSONを再フォーマットして保存することで、コメントを除去できます。

var options = new JsonDocumentOptions
{
    CommentHandling = JsonCommentHandling.Skip
};
string jsonWithComments = @"
{
    // コメント行
    ""Key"": ""Value""
}";
using var doc = JsonDocument.Parse(jsonWithComments, options);
string formattedJson = JsonSerializer.Serialize(doc.RootElement, new JsonSerializerOptions { WriteIndented = true });
Console.WriteLine(formattedJson);
{
  "Key": "Value"
}

コメントが除去され、整形されたJSONが得られます。

落とし穴と対策

循環参照の検出と回避

オブジェクト間で相互に参照し合う「循環参照」がある場合、JSONシリアライズ時に無限ループや例外が発生しやすいです。

特に親子関係や双方向のナビゲーションプロパティを持つクラスで注意が必要です。

  • System.Text.Jsonの場合

デフォルトでは循環参照を検出するとJsonExceptionが発生します。

現状、循環参照を自動的に解決する機能は限定的で、ReferenceHandler.Preserveを使うことで循環参照をサポートできますが、JSONに特殊な$id$refプロパティが挿入されるため、互換性に注意が必要です。

var options = new JsonSerializerOptions
{
    ReferenceHandler = System.Text.Json.Serialization.ReferenceHandler.Preserve,
    WriteIndented = true
};
  • Newtonsoft.Jsonの場合

ReferenceLoopHandling設定で循環参照を無視したり、エラーを回避できます。

var settings = new JsonSerializerSettings
{
    ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};
  • 回避策
    • 循環参照のあるプロパティに[JsonIgnore]を付けて除外する
    • DTO(データ転送オブジェクト)を用いて循環参照を持たない構造に変換する
    • ReferenceHandler.PreserveReferenceLoopHandling.Ignoreを適切に設定する

大文字小文字の取り扱い差異

JSONのキー名は大文字小文字を区別しますが、C#のプロパティ名はPascalCaseが一般的です。

System.Text.JsonNewtonsoft.Jsonではデフォルトの大文字小文字の扱いに違いがあります。

  • System.Text.Json

デフォルトでプロパティ名をそのまま出力し、大文字小文字を区別します。

逆シリアル化時も大文字小文字を厳密にマッチさせるため、JSONのキー名が異なるとマッピングされません。

  • Newtonsoft.Json

デフォルトで大文字小文字を区別しません。

JSONのキー名がnameでもNameでもマッピング可能です。

  • 対策
    • System.Text.Jsonで大文字小文字を無視したい場合は、JsonSerializerOptions.PropertyNameCaseInsensitivetrueに設定します
var options = new JsonSerializerOptions
{
    PropertyNameCaseInsensitive = true
};
  • JSONのキー名を属性やPropertyNamingPolicyで統一します

既定値の扱いで発生する抜け漏れ

シリアル化時にプロパティの既定値(例えばintの0やboolのfalse)が省略されることがあります。

これにより、JSONに期待したキーが含まれず、逆シリアル化時に値が欠落する問題が起こることがあります。

  • System.Text.Json

DefaultIgnoreConditionWhenWritingDefaultに設定すると、既定値のプロパティは出力されません。

var options = new JsonSerializerOptions
{
    DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingDefault
};
  • Newtonsoft.Json

DefaultValueHandlingIgnoreに設定すると同様の動作になります。

  • 対策
    • 既定値を省略したくない場合は、これらの設定をNeverIncludeに変更します
    • 省略されることを前提に、逆シリアル化後のデフォルト値を考慮した設計にします

非同期処理とパフォーマンス低下

JSONのシリアル化・逆シリアル化はCPU負荷が高い処理であり、非同期メソッドを使っても必ずしもパフォーマンスが向上するとは限りません。

  • System.Text.Json

JsonSerializer.SerializeAsyncDeserializeAsyncはストリームを非同期に読み書きしますが、シリアル化自体は同期的に行われる部分もあります。

大量データのI/O待ちを減らせますが、CPU処理は非同期化されません。

  • Newtonsoft.Json

非同期APIは限定的で、主に同期的な処理が中心です。

  • パフォーマンス低下の原因
    • 非同期処理のオーバーヘッド
    • 大量データのシリアル化でCPU負荷が高い
    • ストリームのバッファサイズが小さい場合の頻繁なI/O
  • 対策
    • 非同期APIはI/O待ちがボトルネックのときに使う
    • バッファサイズを適切に設定し、I/O回数を減らす
    • CPU負荷が高い場合はシリアル化処理を別スレッドやバッチ処理に分散する

これらの落とし穴を理解し、適切な設定や設計を行うことで、JSON処理の安定性とパフォーマンスを向上させられます。

セキュリティと安定性

特殊文字のエスケープ

JSON文字列内に含まれる特殊文字は適切にエスケープしないと、クロスサイトスクリプティング(XSS)などのセキュリティリスクを招く可能性があります。

特にWebアプリケーションでJSONをHTMLに埋め込む場合は注意が必要です。

XSS対策としてのEncoder設定

System.Text.Jsonでは、JsonSerializerOptions.Encoderプロパティを設定することで、エスケープ処理をカスタマイズできます。

デフォルトではJavaScriptEncoder.Defaultが使われ、基本的なエスケープは行われますが、HTMLタグや特定のUnicode文字を含む場合は追加のエスケープが必要です。

using System.Text.Encodings.Web;
using System.Text.Unicode;
var options = new JsonSerializerOptions
{
    Encoder = JavaScriptEncoder.Create(UnicodeRanges.BasicLatin, UnicodeRanges.CjkUnifiedIdeographs),
    WriteIndented = true
};
var data = new { Text = "<script>alert('XSS')</script>あいう" };
string jsonString = JsonSerializer.Serialize(data, options);
Console.WriteLine(jsonString);
{
  "Text": "\u003cscript\u003ealert('XSS')\u003c/script\u003eあいう"
}

この例では、<>などのHTMLタグに使われる文字がUnicodeエスケープされ、ブラウザでのスクリプト実行を防止します。

JavaScriptEncoder.Createで許可するUnicode範囲を指定し、必要な文字だけをエスケープ対象から除外できます。

無効化時の注意点

エスケープ処理を無効化したり、カスタムエンコーダーでエスケープを緩めると、XSS攻撃のリスクが高まります。

特にユーザー入力を含むJSONをHTMLに埋め込む場合は、必ず適切なエスケープを行うことが重要です。

また、Newtonsoft.JsonではStringEscapeHandlingプロパティでエスケープの強度を調整できますが、こちらも無効化は推奨されません。

型情報漏洩の防止

JSONに型情報を含める機能は便利ですが、悪意ある攻撃者に型情報を利用されると、リモートコード実行などの深刻な脆弱性につながる恐れがあります。

$typeプロパティの制御

Newtonsoft.JsonTypeNameHandlingを有効にすると、JSONに$typeプロパティが埋め込まれ、逆シリアル化時に型を特定してインスタンス化します。

{
  "$type": "Namespace.ClassName, AssemblyName",
  "Property": "Value"
}

この機能は便利ですが、信頼できないJSONを処理すると、任意の型を生成されてしまうリスクがあります。

  • 対策
    • TypeNameHandlingは必要最低限の範囲でのみ有効にします
    • SerializationBinder(またはISerializationBinder)を実装し、許可する型を限定します
    • 信頼できない入力に対してはTypeNameHandlingを無効にします

System.Text.Jsonはデフォルトで型情報を埋め込まないため、このリスクは低いですが、カスタム実装時は注意が必要です。

過剰データへの耐性

大量のデータや深いネスト構造のJSONを処理する際、メモリ不足やスタックオーバーフロー、DoS攻撃のリスクがあります。

これらを防ぐために、読み取り時の制限を設けることが重要です。

最大デプス設定

System.Text.JsonJsonSerializerOptions.MaxDepthで、JSONの最大ネスト深度を制限できます。

デフォルトは64ですが、必要に応じて調整可能です。

var options = new JsonSerializerOptions
{
    MaxDepth = 32
};

深すぎるネストは例外JsonExceptionを発生させて処理を中断し、過剰なリソース消費を防ぎます。

Newtonsoft.JsonでもJsonSerializerSettings.MaxDepthで同様の制限が可能です。

ストリーム読み取りの制限

ストリームからJSONを読み込む際は、読み取りサイズやタイムアウトを制御して、過剰なデータ受信を防ぎます。

例えば、StreamReaderのバッファサイズを適切に設定したり、CancellationTokenを使ってタイムアウトを設ける方法があります。

また、Web APIなどではリクエストボディの最大サイズをサーバー側で制限し、不正な大量データの送信を防止します。

これらのセキュリティと安定性のポイントを押さえ、JSON処理を安全かつ堅牢に実装することが重要です。

パフォーマンス向上のヒント

バッファ再利用とArrayPool

JSONのシリアル化や逆シリアル化では、一時的にバイト配列や文字配列のバッファを大量に確保することが多く、これがGC(ガベージコレクション)の負荷増大やパフォーマンス低下の原因になります。

ArrayPool<T>を活用すると、バッファの再利用が可能になり、メモリ割り当てを大幅に削減できます。

System.Buffers.ArrayPool<T>は、共有プールから配列を借りて使い終わったら返却する仕組みです。

これにより、頻繁な配列の新規確保を避けられます。

using System;
using System.Buffers;
using System.Text;
using System.Text.Json;
public class Program
{
    public static void Main()
    {
        var pool = ArrayPool<byte>.Shared;
        byte[] buffer = pool.Rent(1024); // 1024バイトのバッファを借りる
        try
        {
            var writer = new Utf8JsonWriter(buffer.AsSpan());
            writer.WriteStartObject();
            writer.WriteString("message", "Hello ArrayPool!");
            writer.WriteEndObject();
            writer.Flush();
            string json = Encoding.UTF8.GetString(buffer, 0, (int)writer.BytesCommitted);
            Console.WriteLine(json);
        }
        finally
        {
            pool.Return(buffer); // バッファをプールに返却
        }
    }
}
{"message":"Hello ArrayPool!"}

このように、ArrayPoolを使うことでバッファの再利用ができ、GCの発生を抑えつつ高速なJSON書き込みが可能です。

特に大量のJSON処理や高頻度のシリアル化処理で効果が大きいです。

Span/Memoryの活用ポイント

Span<T>Memory<T>は、.NETで導入されたメモリ効率の良いデータ操作のための構造体です。

これらを活用すると、配列や文字列のコピーを減らし、パフォーマンスを向上させられます。

  • Span<T>

スタック上に割り当てられ、範囲を指定して配列やメモリの一部を参照できます。

高速でGCの影響を受けませんが、非同期処理には使えません。

  • Memory<T>

ヒープ上に割り当てられ、非同期処理でも使えます。

Span<T>に変換可能です。

System.Text.JsonUtf8JsonWriterUtf8JsonReaderSpan<byte>ReadOnlySpan<byte>を使って高速にバッファを操作しています。

using System;
using System.Text;
using System.Text.Json;
public class Program
{
    public static void Main()
    {
        Span<byte> buffer = stackalloc byte[256]; // スタック上にバッファ確保
        var writer = new Utf8JsonWriter(buffer);
        writer.WriteStartObject();
        writer.WriteString("status", "OK");
        writer.WriteNumber("code", 200);
        writer.WriteEndObject();
        writer.Flush();
        string json = Encoding.UTF8.GetString(buffer.Slice(0, (int)writer.BytesCommitted));
        Console.WriteLine(json);
    }
}
{"status":"OK","code":200}

この例では、スタック上のバッファを直接使うため、ヒープ割り当てが発生せず高速です。

SpanMemoryを活用することで、余計なコピーや割り当てを減らし、効率的なJSON処理が可能になります。

シリアライザインスタンスのキャッシュ

System.Text.JsonJsonSerializerは静的メソッドで使うことが多いですが、JsonSerializerOptionsのインスタンスは使い回すことでパフォーマンスが向上します。

毎回新規にオプションを作成すると、内部での設定解析やキャッシュが無駄になります。

using System;
using System.Text.Json;
public class Program
{
    private static readonly JsonSerializerOptions CachedOptions = new JsonSerializerOptions
    {
        WriteIndented = true,
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase
    };
    public static void Main()
    {
        var obj = new { Name = "Cache", Value = 123 };
        // オプションを使い回すことで高速化
        string json1 = JsonSerializer.Serialize(obj, CachedOptions);
        string json2 = JsonSerializer.Serialize(obj, CachedOptions);
        Console.WriteLine(json1);
        Console.WriteLine(json2);
    }
}
{
  "name": "Cache",
  "value": 123
}
{
  "name": "Cache",
  "value": 123
}

同じJsonSerializerOptionsを複数回使うことで、内部の型情報キャッシュやコンバーターの初期化コストを削減できます。

特に大量のシリアル化処理がある場合は、オプションのキャッシュが効果的です。

また、カスタムコンバーターを登録したオプションは使い回すことが推奨されます。

逆に毎回新規作成するとパフォーマンスが低下します。

これらのテクニックを組み合わせることで、C#でのJSONシリアル化・逆シリアル化のパフォーマンスを大幅に向上させられます。

まとめ

この記事では、C#でJSONを作成・整形・カスタム変換するための代表的なライブラリであるSystem.Text.JsonNewtonsoft.Jsonの使い方や特徴を詳しく解説しました。

基本的なシリアル化から属性設定、カスタムコンバーターの作成、パフォーマンス最適化、セキュリティ対策まで幅広くカバーしています。

用途や要件に応じて適切なライブラリを選び、効率的かつ安全にJSON処理を実装するための知識が身につきます。

関連記事

Back to top button
目次へ