.NET 内で JSON のシリアル化と逆シリアル化 (マーシャリングとマーシャリングの解除) を行う方法How to serialize and deserialize (marshal and unmarshal) JSON in .NET

この記事では、System.Text.Json 名前空間を使用して JavaScript Object Notation (JSON) のシリアル化と逆シリアル化を行う方法について説明します。This article shows how to use the System.Text.Json namespace to serialize and deserialize to and from JavaScript Object Notation (JSON). Newtonsoft.Json から既存のコードを移植する場合は、System.Text.Json に移行する方法に関する記事を参照してください。If you're porting existing code from Newtonsoft.Json, see How to migrate to System.Text.Json.

指示とサンプル コードでは、ライブラリを ASP.NET Core などのフレームワーク経由ではなく直接使用します。The directions and sample code use the library directly, not through a framework such as ASP.NET Core.

シリアル化のサンプル コードの大部分では、JSON を "整形" するために JsonSerializerOptions.WriteIndentedtrue に設定します (人間が読みやすいようにインデントと空白文字が使用されます)。Most of the serialization sample code sets JsonSerializerOptions.WriteIndented to true to "pretty-print" the JSON (with indentation and whitespace for human readability). 実稼働環境で使用する場合、通常、この設定には既定値の false をそのまま使用します。For production use, you would typically accept the default value of false for this setting.

コード例では、次のクラスとそのバリアントを参照しています。The code examples refer to the following class and variants of it:

public class WeatherForecast
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string Summary { get; set; }
}

名前空間Namespaces

System.Text.Json 名前空間には、すべてのエントリ ポイントと主要な型が含まれています。The System.Text.Json namespace contains all the entry points and the main types. System.Text.Json.Serialization 名前空間には、シリアル化と逆シリアル化に固有の高度なシナリオとカスタマイズのための属性と API が含まれています。The System.Text.Json.Serialization namespace contains attributes and APIs for advanced scenarios and customization specific to serialization and deserialization. この記事に示されているコード例では、次のいずれかまたは両方の名前空間に using ディレクティブが必要です。The code examples shown in this article require using directives for one or both of these namespaces:

using System.Text.Json;
using System.Text.Json.Serialization;

System.Runtime.Serialization 名前空間からの属性は、現在 System.Text.Jsonではサポートされていません。Attributes from the System.Runtime.Serialization namespace aren't currently supported in System.Text.Json.

.NET オブジェクトを JSON に書き込む方法 (シリアル化)How to write .NET objects to JSON (serialize)

JSON を文字列またはファイルに書き込むには、JsonSerializer.Serialize メソッドを呼び出します。To write JSON to a string or to a file, call the JsonSerializer.Serialize method.

次の例では、JSON を文字列として作成します。The following example creates JSON as a string:

string jsonString;
jsonString = JsonSerializer.Serialize(weatherForecast);

次の例では、同期コードを使用して JSON ファイルを作成します。The following example uses synchronous code to create a JSON file:

jsonString = JsonSerializer.Serialize(weatherForecast);
File.WriteAllText(fileName, jsonString);

次の例では、非同期コードを使用して JSON ファイルを作成します。The following example uses asynchronous code to create a JSON file:

using (FileStream fs = File.Create(fileName))
{
    await JsonSerializer.SerializeAsync(fs, weatherForecast);
}

前の例では、シリアル化する型に型の推定を使用しています。The preceding examples use type inference for the type being serialized. Serialize() のオーバーロードでは、ジェネリック型パラメーターを受け取ります。An overload of Serialize() takes a generic type parameter:

jsonString = JsonSerializer.Serialize<WeatherForecastWithPOCOs>(weatherForecast);

シリアル化の例Serialization example

コレクションと入れ子になったクラスを含むクラスの例を次に示します。Here's an example class that contains collections and a nested class:

public class WeatherForecastWithPOCOs
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string Summary { get; set; }
    public string SummaryField;
    public IList<DateTimeOffset> DatesAvailable { get; set; }
    public Dictionary<string, HighLowTemps> TemperatureRanges { get; set; }
    public string[] SummaryWords { get; set; }
}

public class HighLowTemps
{
    public int High { get; set; }
    public int Low { get; set; }
}

前の型のインスタンスをシリアル化した場合の JSON 出力は、次の例のようになります。The JSON output from serializing an instance of the preceding type looks like the following example. JSON 出力は既定で縮小されます。The JSON output is minified by default:

{"Date":"2019-08-01T00:00:00-07:00","TemperatureCelsius":25,"Summary":"Hot","DatesAvailable":["2019-08-01T00:00:00-07:00","2019-08-02T00:00:00-07:00"],"TemperatureRanges":{"Cold":{"High":20,"Low":-10},"Hot":{"High":60,"Low":20}},"SummaryWords":["Cool","Windy","Humid"]}

次の例では、同じ JSON が書式設定されて示されています (空白とインデントで整形されています)。The following example shows the same JSON, formatted (that is, pretty-printed with whitespace and indentation):

{
  "Date": "2019-08-01T00:00:00-07:00",
  "TemperatureCelsius": 25,
  "Summary": "Hot",
  "DatesAvailable": [
    "2019-08-01T00:00:00-07:00",
    "2019-08-02T00:00:00-07:00"
  ],
  "TemperatureRanges": {
    "Cold": {
      "High": 20,
      "Low": -10
    },
    "Hot": {
      "High": 60,
      "Low": 20
    }
  },
  "SummaryWords": [
    "Cool",
    "Windy",
    "Humid"
  ]
}

UTF-8 にシリアル化するSerialize to UTF-8

UTF-8 にシリアル化するには、JsonSerializer.SerializeToUtf8Bytes メソッドを呼び出します。To serialize to UTF-8, call the JsonSerializer.SerializeToUtf8Bytes method:

byte[] jsonUtf8Bytes;
var options = new JsonSerializerOptions
{
    WriteIndented = true
};
jsonUtf8Bytes = JsonSerializer.SerializeToUtf8Bytes(weatherForecast, options);

Utf8JsonWriter を受け取る Serialize オーバーロードも使用できます。A Serialize overload that takes a Utf8JsonWriter is also available.

UTF-8 へのシリアル化は、文字列ベースのメソッドを使用するよりも約 5-10% 高速です。Serializing to UTF-8 is about 5-10% faster than using the string-based methods. 違いは、バイト (UTF-8) を文字列 (UTF-16) に変換する必要がないことから生じます。The difference is because the bytes (as UTF-8) don't need to be converted to strings (UTF-16).

シリアル化の動作Serialization behavior

サポートされる型には次のようなものがあります。Supported types include:

  • 数値型、文字列、ブール値など、JavaScript プリミティブにマップされる .NET プリミティブ。.NET primitives that map to JavaScript primitives, such as numeric types, strings, and Boolean.
  • ユーザー定義の Plain Old CLR Objects (POCO)User-defined Plain Old CLR Objects (POCOs).
  • 1 次元配列とジャグ配列 (ArrayName[][])。One-dimensional and jagged arrays (ArrayName[][]).
  • Dictionary<string,TValue>TValueobjectJsonElement、または POCO です。Dictionary<string,TValue> where TValue is object, JsonElement, or a POCO.
  • 次の名前空間からのコレクション。Collections from the following namespaces.

カスタム コンバーターを実装して、追加の型を処理したり、組み込みコンバーターではサポートされていない機能を提供したりすることができます。You can implement custom converters to handle additional types or to provide functionality that isn't supported by the built-in converters.

JSON を .NET オブジェクトに読み取る方法 (逆シリアル化)How to read JSON into .NET objects (deserialize)

文字列またはファイルから逆シリアル化するには、JsonSerializer.Deserialize メソッドを呼び出します。To deserialize from a string or a file, call the JsonSerializer.Deserialize method.

次の例では、文字列から JSON を読み取り、前にシリアル化の例で示した WeatherForecast クラスのインスタンスを作成します。The following example reads JSON from a string and creates an instance of the WeatherForecast class shown earlier for the serialization example:

weatherForecast = JsonSerializer.Deserialize<WeatherForecastWithPOCOs>(jsonString);

同期コードを使用してファイルから逆シリアル化するには、次の例に示すように、ファイルを文字列に読み取ります。To deserialize from a file by using synchronous code, read the file into a string, as shown in the following example:

jsonString = File.ReadAllText(fileName);
weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(jsonString);

非同期コードを使用してファイルから逆シリアル化するには、DeserializeAsync メソッドを呼び出します。To deserialize from a file by using asynchronous code, call the DeserializeAsync method:

using (FileStream fs = File.OpenRead(fileName))
{
    weatherForecast = await JsonSerializer.DeserializeAsync<WeatherForecast>(fs);
}

UTF-8 からの逆シリアル化Deserialize from UTF-8

UTF-8 から逆シリアル化するには、次の例に示すように、Utf8JsonReader または ReadOnlySpan<byte> を受け取る JsonSerializer.Deserialize オーバーロードを呼び出します。To deserialize from UTF-8, call a JsonSerializer.Deserialize overload that takes a Utf8JsonReader or a ReadOnlySpan<byte>, as shown in the following examples. この例では、JSON が jsonUtf8Bytes という名前のバイト配列内にあることを想定しています。The examples assume the JSON is in a byte array named jsonUtf8Bytes.

var readOnlySpan = new ReadOnlySpan<byte>(jsonUtf8Bytes);
weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(readOnlySpan);
var utf8Reader = new Utf8JsonReader(jsonUtf8Bytes);
weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(ref utf8Reader);

逆シリアル化の動作Deserialization behavior

  • 既定では、プロパティ名の照合では大文字と小文字が区別されます。By default, property name matching is case-sensitive. 大文字と小文字を区別しないことを指定できます。You can specify case-insensitivity.
  • JSON に読み取り専用プロパティの値が含まれている場合、その値は無視され、例外はスローされません。If the JSON contains a value for a read-only property, the value is ignored and no exception is thrown.
  • パラメーターなしのコンストラクターがない参照型への逆シリアル化はサポートされていません。Deserialization to reference types without a parameterless constructor isn't supported.
  • 不変オブジェクトまたは読み取り専用プロパティへの逆シリアル化はサポートされていません。Deserialization to immutable objects or read-only properties isn't supported.
  • 既定では、列挙型は数値としてサポートされています。By default, enums are supported as numbers. 列挙型名を文字列としてシリアル化することができます。You can serialize enum names as strings.
  • フィールドはサポートされません。Fields aren't supported.
  • 既定では、JSON にコメントまたは末尾のコンマがあると例外がスローされます。By default, comments or trailing commas in the JSON throw exceptions. コメントと末尾のコンマを許可することができます。You can allow comments and trailing commas.
  • 既定の最大深度は 64 です。The default maximum depth is 64.

カスタム コンバーターを実装して、組み込みコンバーターではサポートされていない機能を提供できます。You can implement custom converters to provide functionality that isn't supported by the built-in converters.

書式設定された JSON へのシリアル化Serialize to formatted JSON

JSON 出力を整形するには、JsonSerializerOptions.WriteIndentedtrue に設定します。To pretty-print the JSON output, set JsonSerializerOptions.WriteIndented to true:

var options = new JsonSerializerOptions
{
    WriteIndented = true,
};
jsonString = JsonSerializer.Serialize(weatherForecast, options);

シリアル化され、整形された JSON 出力の型の例を次に示します。Here's an example type to be serialized and pretty-printed JSON output:

public class WeatherForecast
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string Summary { get; set; }
}
{
  "Date": "2019-08-01T00:00:00-07:00",
  "TemperatureCelsius": 25,
  "Summary": "Hot"
}

JSON の名前と値をカスタマイズするCustomize JSON names and values

既定では、プロパティ名とディクショナリ キーは、大文字と小文字の区別を含め、JSON の出力では変更されません。By default, property names and dictionary keys are unchanged in the JSON output, including case. 列挙型の値は数値として表されます。Enum values are represented as numbers. このセクションでは、次の方法について説明します。This section explains how to:

JSON プロパティの名前と値の特別な処理を必要とするその他のシナリオでは、カスタム コンバーターを実装することができます。For other scenarios that require special handling of JSON property names and values, you can implement custom converters.

個々のプロパティ名をカスタマイズするCustomize individual property names

個々のプロパティの名前を設定するには、[JsonPropertyName] 属性を使用します。To set the name of individual properties, use the [JsonPropertyName] attribute.

シリアル化する型と、結果として得られる JSON の例を次に示します。Here's an example type to serialize and resulting JSON:

public class WeatherForecastWithPropertyNameAttribute
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string Summary { get; set; }
    [JsonPropertyName("Wind")]
    public int WindSpeed { get; set; }
}
{
  "Date": "2019-08-01T00:00:00-07:00",
  "TemperatureCelsius": 25,
  "Summary": "Hot",
  "Wind": 35
}

この属性によって設定されるプロパティ名は:The property name set by this attribute:

  • シリアル化と逆シリアル化の両方の方向に適用されます。Applies in both directions, for serialization and deserialization.
  • プロパティの名前付けポリシーよりも優先されます。Takes precedence over property naming policies.

すべての JSON プロパティ名にキャメル ケースを使用するUse camel case for all JSON property names

すべての JSON プロパティ名にキャメル ケースを使用するには、次の例に示すように、JsonSerializerOptions.PropertyNamingPolicyJsonNamingPolicy.CamelCase に設定します。To use camel case for all JSON property names, set JsonSerializerOptions.PropertyNamingPolicy to JsonNamingPolicy.CamelCase, as shown in the following example:

var serializeOptions = new JsonSerializerOptions
{
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
    WriteIndented = true
};
jsonString = JsonSerializer.Serialize(weatherForecast, serializeOptions);

シリアル化するクラスと JSON 出力の例を次に示します。Here's an example class to serialize and JSON output:

public class WeatherForecastWithPropertyNameAttribute
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string Summary { get; set; }
    [JsonPropertyName("Wind")]
    public int WindSpeed { get; set; }
}
{
  "date": "2019-08-01T00:00:00-07:00",
  "temperatureCelsius": 25,
  "summary": "Hot",
  "Wind": 35
}

キャメル ケースのプロパティの名前付けポリシーは:The camel case property naming policy:

  • シリアル化と逆シリアル化に適用されます。Applies to serialization and deserialization.
  • [JsonPropertyName] 属性によってオーバーライドされます。Is overridden by [JsonPropertyName] attributes. このため、この例の JSON プロパティ名 Wind はキャメル ケースではありません。This is why the JSON property name Wind in the example is not camel case.

カスタム JSON プロパティの名前付けポリシーを使用するUse a custom JSON property naming policy

カスタム JSON プロパティの名前付けポリシーを使用するには、次の例に示すように、JsonNamingPolicy から派生するクラスを作成し、ConvertName メソッドをオーバーライドします。To use a custom JSON property naming policy, create a class that derives from JsonNamingPolicy and override the ConvertName method, as shown in the following example:

using System.Text.Json;

namespace SystemTextJsonSamples
{
    public class UpperCaseNamingPolicy : JsonNamingPolicy
    {
        public override string ConvertName(string name) =>
            name.ToUpper();
    }
}

次に、JsonSerializerOptions.PropertyNamingPolicy プロパティを名前付けポリシー クラスのインスタンスに設定します。Then set the JsonSerializerOptions.PropertyNamingPolicy property to an instance of your naming policy class:

var options = new JsonSerializerOptions
{
    PropertyNamingPolicy = new UpperCaseNamingPolicy(),
    WriteIndented = true
};
jsonString = JsonSerializer.Serialize(weatherForecast, options);

シリアル化するクラスと JSON 出力の例を次に示します。Here's an example class to serialize and JSON output:

public class WeatherForecastWithPropertyNameAttribute
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string Summary { get; set; }
    [JsonPropertyName("Wind")]
    public int WindSpeed { get; set; }
}
{
  "DATE": "2019-08-01T00:00:00-07:00",
  "TEMPERATURECELSIUS": 25,
  "SUMMARY": "Hot",
  "Wind": 35
}

JSON プロパティの名前付けポリシーは:The JSON property naming policy:

  • シリアル化と逆シリアル化に適用されます。Applies to serialization and deserialization.
  • [JsonPropertyName] 属性によってオーバーライドされます。Is overridden by [JsonPropertyName] attributes. このため、この例の JSON プロパティ名 Wind は大文字ではありません。This is why the JSON property name Wind in the example is not upper case.

キャメル ケースのディクショナリ キーCamel case dictionary keys

シリアル化するオブジェクトのプロパティが Dictionary<string,TValue> 型である場合は、string キーをキャメル ケースに変換できます。If a property of an object to be serialized is of type Dictionary<string,TValue>, the string keys can be converted to camel case. これを行うには、次の例に示すように、DictionaryKeyPolicyJsonNamingPolicy.CamelCase に設定します。To do that, set DictionaryKeyPolicy to JsonNamingPolicy.CamelCase, as shown in the following example:

var options = new JsonSerializerOptions
{
    DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
    WriteIndented = true
};
jsonString = JsonSerializer.Serialize(weatherForecast, options);

キーと値のペア "ColdMinTemp", 20 および "HotMinTemp", 40 を持つ TemperatureRanges という名前のディクショナリを使用してオブジェクトをシリアル化すると、次の例のような JSON 出力が生成されます。Serializing an object with a dictionary named TemperatureRanges that has key-value pairs "ColdMinTemp", 20 and "HotMinTemp", 40 would result in JSON output like the following example:

{
  "Date": "2019-08-01T00:00:00-07:00",
  "TemperatureCelsius": 25,
  "Summary": "Hot",
  "TemperatureRanges": {
    "coldMinTemp": 20,
    "hotMinTemp": 40
  }
}

ディクショナリ キーに対するキャメル ケースの名前付けポリシーは、シリアル化にのみ適用されます。The camel case naming policy for dictionary keys applies to serialization only. ディクショナリを逆シリアル化すると、DictionaryKeyPolicyJsonNamingPolicy.CamelCase を指定した場合でも、キーが JSON ファイルと一致します。If you deserialize a dictionary, the keys will match the JSON file even if you specify JsonNamingPolicy.CamelCase for the DictionaryKeyPolicy.

文字列としての列挙型Enums as strings

既定では、列挙型は数値としてシリアル化されます。By default, enums are serialized as numbers. 列挙型名を文字列としてシリアル化するには、JsonStringEnumConverter を使用します。To serialize enum names as strings, use the JsonStringEnumConverter.

たとえば、列挙型を持つ次のクラスをシリアル化する必要があるとします。For example, suppose you need to serialize the following class that has an enum:

public class WeatherForecastWithEnum
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public Summary Summary { get; set; }
}

public enum Summary
{
    Cold, Cool, Warm, Hot
}

Summary が Hot の場合、既定では、シリアル化された JSON には数値 3 があります。If the Summary is Hot, by default the serialized JSON has the numeric value 3:

{
  "Date": "2019-08-01T00:00:00-07:00",
  "TemperatureCelsius": 25,
  "Summary": 3
}

次のサンプル コードでは、数値ではなく列挙型名をシリアル化し、名前をキャメル ケースに変換します。The following sample code serializes the enum names instead of the numeric values, and converts the names to camel case:

options = new JsonSerializerOptions();
options.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase));
options.WriteIndented = true;
jsonString = JsonSerializer.Serialize(weatherForecast, options);

結果として生成される JSON は、次の例のようになります。The resulting JSON looks like the following example:

{
  "Date": "2019-08-01T00:00:00-07:00",
  "TemperatureCelsius": 25,
  "Summary": "hot"
}

列挙型の文字列名も、次の例に示すように逆シリアル化できます。Enum string names can be deserialized as well, as shown in the following example:

options = new JsonSerializerOptions();
options.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase));
weatherForecast = JsonSerializer.Deserialize<WeatherForecastWithEnum>(jsonString, options);

シリアル化からプロパティを除外するExclude properties from serialization

既定では、すべてのパブリック プロパティがシリアル化されます。By default, all public properties are serialized. その一部が JSON 出力に出現しないようにするには、いくつかのオプションがあります。If you don't want some of them to appear in the JSON output, you have several options. このセクションでは、以下を除外する方法について説明します。This section explains how to exclude:

個々のプロパティを除外するExclude individual properties

個々のプロパティを無視するには、[JsonIgnore] 属性を使用します。To ignore individual properties, use the [JsonIgnore] attribute.

シリアル化する型と JSON 出力の例を次に示します。Here's an example type to serialize and JSON output:

public class WeatherForecastWithIgnoreAttribute
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    [JsonIgnore]
    public string Summary { get; set; }
}
{
  "Date": "2019-08-01T00:00:00-07:00",
  "TemperatureCelsius": 25,
}

すべての読み取り専用プロパティを除外するExclude all read-only properties

パブリック ゲッターが含まれていてもパブリック セッターがない場合、プロパティは読み取り専用です。A property is read-only if it contains a public getter but not a public setter. すべての読み取り専用プロパティを除外するには、次の例に示すように、JsonSerializerOptions.IgnoreReadOnlyPropertiestrue に設定します。To exclude all read-only properties, set the JsonSerializerOptions.IgnoreReadOnlyProperties to true, as shown in the following example:

var options = new JsonSerializerOptions
{
    IgnoreReadOnlyProperties = true,
    WriteIndented = true
};
jsonString = JsonSerializer.Serialize(weatherForecast, options);

シリアル化する型と JSON 出力の例を次に示します。Here's an example type to serialize and JSON output:

public class WeatherForecastWithROProperty
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string Summary { get; set; }
    public int WindSpeedReadOnly { get; private set; } = 35;
}
{
  "Date": "2019-08-01T00:00:00-07:00",
  "TemperatureCelsius": 25,
  "Summary": "Hot",
}

このオプションは、シリアル化にのみ適用されます。This option applies only to serialization. 逆シリアル化中、既定では読み取り専用プロパティが無視されます。During deserialization, read-only properties are ignored by default.

すべての null 値プロパティを除外するExclude all null value properties

すべての null 値プロパティを除外するには、次の例に示すように、IgnoreNullValues プロパティを true に設定します。To exclude all null value properties, set the IgnoreNullValues property to true, as shown in the following example:

var options = new JsonSerializerOptions
{
    IgnoreNullValues = true,
    WriteIndented = true
};
jsonString = JsonSerializer.Serialize(weatherForecast, options);

シリアル化するオブジェクトと JSON 出力の例を次に示します。Here's an example object to serialize and JSON output:

プロパティProperty [値]Value
DateDate 8/1/2019 12:00:00 AM -07:008/1/2019 12:00:00 AM -07:00
TemperatureCelsiusTemperatureCelsius 2525
まとめSummary nullnull
{
  "Date": "2019-08-01T00:00:00-07:00",
  "TemperatureCelsius": 25
}

この設定はシリアル化と逆シリアル化に適用されます。This setting applies to serialization and deserialization. 逆シリアル化に対する影響については、「逆シリアル化時に null を無視する」を参照してください。For information about its effect on deserialization, see Ignore null when deserializing.

文字エンコードをカスタマイズするCustomize character encoding

既定では、シリアライザーでは ASCII 以外のすべての文字がエスケープされます。By default, the serializer escapes all non-ASCII characters. つまり、\uxxxx に置き換えられます。xxxx は文字の Unicode コードです。That is, it replaces them with \uxxxx where xxxx is the Unicode code of the character. たとえば、Summary プロパティがキリル文字の жарко に設定されている場合、WeatherForecast オブジェクトは次の例に示すようにシリアル化されます。For example, if the Summary property is set to Cyrillic жарко, the WeatherForecast object is serialized as shown in this example:

{
  "Date": "2019-08-01T00:00:00-07:00",
  "TemperatureCelsius": 25,
  "Summary": "\u0436\u0430\u0440\u043A\u043E"
}

言語文字セットのシリアル化Serialize language character sets

1 つ以上の言語の文字セットをエスケープせずにシリアル化するには、次の例に示すように、System.Text.Encodings.Web.JavaScriptEncoder のインスタンスを作成するときに Unicode 範囲を指定します。To serialize the character set(s) of one or more languages without escaping, specify Unicode range(s) when creating an instance of System.Text.Encodings.Web.JavaScriptEncoder, as shown in the following example:

using System;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Unicode;
options = new JsonSerializerOptions
{
    Encoder = JavaScriptEncoder.Create(UnicodeRanges.BasicLatin, UnicodeRanges.Cyrillic),
    WriteIndented = true
};
jsonString = JsonSerializer.Serialize(weatherForecast, options);

このコードでは、キリル文字やギリシャ文字はエスケープされません。This code doesn't escape Cyrillic or Greek characters. Summary プロパティがキリル文字の жарко に設定されている場合、WeatherForecast オブジェクトは次の例に示すようにシリアル化されます。If the Summary property is set to Cyrillic жарко, the WeatherForecast object is serialized as shown in this example:

{
  "Date": "2019-08-01T00:00:00-07:00",
  "TemperatureCelsius": 25,
  "Summary": "жарко"
}

すべての言語セットをエスケープせずにシリアル化するには、UnicodeRanges.All を使用します。To serialize all language sets without escaping, use UnicodeRanges.All.

特定の文字のシリアル化Serialize specific characters

別の方法として、エスケープせずに許可する個々の文字を指定することもできます。An alternative is to specify individual characters that you want to allow through without being escaped. 次の例では、жарко の最初の 2 文字のみをシリアル化します。The following example serializes only the first two characters of жарко:

using System;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Unicode;
var encoderSettings = new TextEncoderSettings();
encoderSettings.AllowCharacters('\u0436', '\u0430');
encoderSettings.AllowRange(UnicodeRanges.BasicLatin);
options = new JsonSerializerOptions
{
    Encoder = JavaScriptEncoder.Create(encoderSettings),
    WriteIndented = true
};
jsonString = JsonSerializer.Serialize(weatherForecast, options);

上記のコードによって生成される JSON の例を次に示します。Here's an example of JSON produced by the preceding code:

{
  "Date": "2019-08-01T00:00:00-07:00",
  "TemperatureCelsius": 25,
  "Summary": "жа\u0440\u043A\u043E"
}

すべての文字のシリアル化Serialize all characters

エスケープを最小化するには、次の例に示すように、JavaScriptEncoder.UnsafeRelaxedJsonEscaping を使用できます。To minimize escaping you can use JavaScriptEncoder.UnsafeRelaxedJsonEscaping, as shown in the following example:

using System;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Unicode;
options = new JsonSerializerOptions
{
    Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
    WriteIndented = true
};
jsonString = JsonSerializer.Serialize(weatherForecast, options);

注意事項

既定のエンコーダーと比較して、UnsafeRelaxedJsonEscaping エンコーダーは、文字をエスケープせずにそのまま渡すことについて、より寛容です。Compared to the default encoder, the UnsafeRelaxedJsonEscaping encoder is more permissive about allowing characters to pass through unescaped:

  • <>&' など、HTML に影響する文字はエスケープされません。It doesn't escape HTML-sensitive characters such as <, >, &, and '.
  • クライアントとサーバーが "文字セット" について合意していない場合の結果など、XSS または情報漏えい攻撃に対する追加の多層防御は提供されません。It doesn't offer any additional defense-in-depth protections against XSS or information disclosure attacks, such as those which might result from the client and server disagreeing on the charset.

安全でないエンコーダーは、クライアントによって結果のペイロードが UTF-8 でエンコードされた JSON として解釈されることがわかっている場合にのみ使用してください。Use the unsafe encoder only when it's known that the client will be interpreting the resulting payload as UTF-8 encoded JSON. たとえば、サーバーが応答ヘッダー Content-Type: application/json; charset=utf-8 を送信している場合は使用できます。For example, you can use it if the server is sending the response header Content-Type: application/json; charset=utf-8. 未加工の UnsafeRelaxedJsonEscaping 出力が HTML ページまたは <script> 要素に決して出力されないようにしてください。Never allow the raw UnsafeRelaxedJsonEscaping output to be emitted into an HTML page or a <script> element.

派生クラスのプロパティのシリアル化Serialize properties of derived classes

ポリモーフィックな型階層のシリアル化はサポートされていません。Serialization of a polymorphic type hierarchy is not supported. たとえば、プロパティがインターフェイスまたは抽象クラスとして定義されている場合は、ランタイム型に追加のプロパティがある場合でも、インターフェイスまたは抽象クラスに定義されたプロパティのみがシリアル化されます。For example, if a property is defined as an interface or an abstract class, only the properties defined on the interface or abstract class are serialized, even if the runtime type has additional properties. この動作の例外については、このセクションで説明します。The exceptions to this behavior are explained in this section.

たとえば、WeatherForecast クラスと派生クラス WeatherForecastDerived があるとします。For example, suppose you have a WeatherForecast class and a derived class WeatherForecastDerived:

public class WeatherForecast
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string Summary { get; set; }
}
public class WeatherForecastDerived : WeatherForecast
{
    public int WindSpeed { get; set; }
}

また、コンパイル時の Serialize メソッドの型引数が WeatherForecast であるとします。And suppose the type argument of the Serialize method at compile time is WeatherForecast:

var options = new JsonSerializerOptions
{
    WriteIndented = true
};
jsonString = JsonSerializer.Serialize<WeatherForecast>(weatherForecast, options);

このシナリオでは、weatherForecast オブジェクトが実際には WeatherForecastDerived オブジェクトであっても、WindSpeed プロパティはシリアル化されません。In this scenario, the WindSpeed property is not serialized even if the weatherForecast object is actually a WeatherForecastDerived object. 基本クラスのプロパティのみがシリアル化されます。Only the base class properties are serialized:

{
  "Date": "2019-08-01T00:00:00-07:00",
  "TemperatureCelsius": 25,
  "Summary": "Hot"
}

この動作は、ランタイムによって作成される派生型内でデータが誤って公開されるのを防ぐためのものです。This behavior is intended to help prevent accidental exposure of data in a derived runtime-created type.

前の例で派生型のプロパティをシリアル化するには、次のいずれかのアプローチを使用します。To serialize the properties of the derived type in the preceding example, use one of the following approaches:

  • 実行時に型を指定できるようにする Serialize のオーバーロードを呼び出します。Call an overload of Serialize that lets you specify the type at run time:

    options = new JsonSerializerOptions
    {
        WriteIndented = true
    };
    jsonString = JsonSerializer.Serialize(weatherForecast, weatherForecast.GetType(), options);
    
  • オブジェクトを object としてシリアル化するように宣言します。Declare the object to be serialized as object.

    options = new JsonSerializerOptions
    {
        WriteIndented = true
    };
    jsonString = JsonSerializer.Serialize<object>(weatherForecast, options);
    

前の例のシナリオでは、どちらのアプローチでも、WindSpeed プロパティが JSON 出力に含まれるようになります。In the preceding example scenario, both approaches cause the WindSpeed property to be included in the JSON output:

{
  "WindSpeed": 35,
  "Date": "2019-08-01T00:00:00-07:00",
  "TemperatureCelsius": 25,
  "Summary": "Hot"
}

重要

これらのアプローチでは、シリアル化するルート オブジェクトに対してのみポリモーフィックなシリアル化が提供され、そのルート オブジェクトのプロパティに対しては提供されません。These approaches provide polymorphic serialization only for the root object to be serialized, not for properties of that root object.

object 型として定義すると、下位レベルのオブジェクトのポリモーフィックなシリアル化を取得できます。You can get polymorphic serialization for lower-level objects if you define them as type object. たとえば、WeatherForecast クラスに、WeatherForecast または object 型として定義できる PreviousForecast という名前のプロパティがあるとします。For example, suppose your WeatherForecast class has a property named PreviousForecast that can be defined as type WeatherForecast or object:

public class WeatherForecastWithPrevious
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string Summary { get; set; }
    public WeatherForecast PreviousForecast { get; set; }
}
public class WeatherForecastWithPreviousAsObject
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string Summary { get; set; }
    public object PreviousForecast { get; set; }
}

PreviousForecast プロパティに WeatherForecastDerived のインスタンスが含まれる場合:If the PreviousForecast property contains an instance of WeatherForecastDerived:

  • WeatherForecastWithPrevious のシリアル化からの JSON 出力には WindSpeed含まれていませんThe JSON output from serializing WeatherForecastWithPrevious doesn't include WindSpeed.
  • WeatherForecastWithPreviousAsObject のシリアル化からの JSON 出力には WindSpeed含まれていますThe JSON output from serializing WeatherForecastWithPreviousAsObject includes WindSpeed.

ルート オブジェクトは派生型である可能性があるものではないため、WeatherForecastWithPreviousAsObject をシリアル化するために Serialize<object> または GetType を呼び出す必要はありません。To serialize WeatherForecastWithPreviousAsObject, it isn't necessary to call Serialize<object> or GetType because the root object isn't the one that may be of a derived type. 次のコード例では Serialize<object> または GetType は呼び出されません。The following code example doesn't call Serialize<object> or GetType:

options = new JsonSerializerOptions
{
    WriteIndented = true
};
jsonString = JsonSerializer.Serialize(weatherForecastWithPreviousAsObject, options);

上記のコードでは、WeatherForecastWithPreviousAsObject が正しくシリアル化されます。The preceding code correctly serializes WeatherForecastWithPreviousAsObject:

{
  "Date": "2019-08-01T00:00:00-07:00",
  "TemperatureCelsius": 25,
  "Summary": "Hot",
  "PreviousForecast": {
    "WindSpeed": 35,
    "Date": "2019-08-01T00:00:00-07:00",
    "TemperatureCelsius": 25,
    "Summary": "Hot"
  }
}

object と同じプロパティ定義のアプローチがインターフェイスで機能します。The same approach of defining properties as object works with interfaces. 次のインターフェイスと実装があり、実装インスタンスを含むプロパティを使用してクラスをシリアル化するとします。Suppose you have the following interface and implementation, and you want to serialize a class with properties that contain implementation instances:

using System;

namespace SystemTextJsonSamples
{
    public interface IForecast
    {
        public DateTimeOffset Date { get; set; }
        public int TemperatureCelsius { get; set; }
        public string Summary { get; set; }
    }

    public class Forecast : IForecast
    {
        public DateTimeOffset Date { get; set; }
        public int TemperatureCelsius { get; set; }
        public string Summary { get; set; }
        public int WindSpeed { get; set; }
    }

    public class Forecasts
    {
        public IForecast Monday { get; set; }
        public object Tuesday { get; set; }
    }
}

Forecasts のインスタンスをシリアル化する場合、Tuesdayobject として定義されているので、Tuesday にのみ WindSpeed プロパティが表示されます。When you serialize an instance of Forecasts, only Tuesday shows the WindSpeed property, because Tuesday is defined as object:

var forecasts = new Forecasts
{
    Monday = new Forecast
    {
        Date = DateTime.Parse("2020-01-06"),
        TemperatureCelsius = 10,
        Summary = "Cool",
        WindSpeed = 8
    },
    Tuesday = new Forecast
    {
        Date = DateTime.Parse("2020-01-07"),
        TemperatureCelsius = 11,
        Summary = "Rainy",
        WindSpeed = 10
    }
};

options = new JsonSerializerOptions
{
    WriteIndented = true
};
jsonString = JsonSerializer.Serialize(forecasts, options);

次の例は、前のコードから生成された JSON を示しています。The following example shows the JSON that results from the preceding code:

{
  "Monday": {
    "Date": "2020-01-06T00:00:00-08:00",
    "TemperatureCelsius": 10,
    "Summary": "Cool"
  },
  "Tuesday": {
    "Date": "2020-01-07T00:00:00-08:00",
    "TemperatureCelsius": 11,
    "Summary": "Rainy",
    "WindSpeed": 10
  }
}

ポリモーフィック シリアル化の詳細、および逆シリアル化の詳細については、「Newtonsoft.Json から System.Text.Json に移行する方法」を参照してください。For more information about polymorphic serialization, and for information about deserialization, see How to migrate from Newtonsoft.Json to System.Text.Json.

コメントと末尾のコンマを許可するAllow comments and trailing commas

既定では、JSON 内でコメントと末尾のコンマは使用できません。By default, comments and trailing commas are not allowed in JSON. JSON 内でコメントを許可するには、JsonSerializerOptions.ReadCommentHandling プロパティを JsonCommentHandling.Skip に設定します。To allow comments in the JSON, set the JsonSerializerOptions.ReadCommentHandling property to JsonCommentHandling.Skip. また、末尾のコンマを許可するには、JsonSerializerOptions.AllowTrailingCommas プロパティを true に設定します。And to allow trailing commas, set the JsonSerializerOptions.AllowTrailingCommas property to true. 両方を許可する方法を次の例に示します。The following example shows how to allow both:

var options = new JsonSerializerOptions
{
    ReadCommentHandling = JsonCommentHandling.Skip,
    AllowTrailingCommas = true,
};
var weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(jsonString, options);

次に、コメントと末尾のコンマを含む JSON の例を示します。Here's example JSON with comments and a trailing comma:

{
  "Date": "2019-08-01T00:00:00-07:00",
  "TemperatureCelsius": 25, // Fahrenheit 77
  "Summary": "Hot", /* Zharko */
}

大文字と小文字を区別しないプロパティ照合Case-insensitive property matching

既定では、逆シリアル化では JSON とターゲット オブジェクトのプロパティとの間で大文字と小文字を区別したプロパティ名の一致が検索されます。By default, deserialization looks for case-sensitive property name matches between JSON and the target object properties. この動作を変更するには、JsonSerializerOptions.PropertyNameCaseInsensitivetrue に設定します。To change that behavior, set JsonSerializerOptions.PropertyNameCaseInsensitive to true:

var options = new JsonSerializerOptions
{
    PropertyNameCaseInsensitive = true,
};
var weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(jsonString, options);

キャメル ケースのプロパティ名を持つ JSON の例を次に示します。Here's example JSON with camel case property names. これはパスカル ケースのプロパティ名を持つ次の型に逆シリアル化できます。It can be deserialized into the following type that has Pascal case property names.

{
  "date": "2019-08-01T00:00:00-07:00",
  "temperatureCelsius": 25,
  "summary": "Hot",
}
public class WeatherForecast
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string Summary { get; set; }
}

オーバーフロー JSON の処理Handle overflow JSON

逆シリアル化中に、ターゲット型のプロパティで表されないデータを JSON 内で受け取ることがあります。While deserializing, you might receive data in the JSON that is not represented by properties of the target type. たとえば、ターゲット型が次のようになっているとします。For example, suppose your target type is this:

public class WeatherForecast
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string Summary { get; set; }
}

逆シリアル化される JSON は次のとおりです。And the JSON to be deserialized is this:

{
  "Date": "2019-08-01T00:00:00-07:00",
  "temperatureCelsius": 25,
  "Summary": "Hot",
  "DatesAvailable": [
    "2019-08-01T00:00:00-07:00",
    "2019-08-02T00:00:00-07:00"
  ],
  "SummaryWords": [
    "Cool",
    "Windy",
    "Humid"
  ]
}

表示されている JSON を示されている型に逆シリアル化すると、DatesAvailableSummaryWords のプロパティは行き先がなくなり、失われます。If you deserialize the JSON shown into the type shown, the DatesAvailable and SummaryWords properties have nowhere to go and are lost. これらのプロパティなどの余分なデータをキャプチャするには、JsonExtensionData 属性を型 Dictionary<string,object> または Dictionary<string,JsonElement> のプロパティに適用します。To capture extra data such as these properties, apply the JsonExtensionData attribute to a property of type Dictionary<string,object> or Dictionary<string,JsonElement>:

public class WeatherForecastWithExtensionData
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string Summary { get; set; }
    [JsonExtensionData]
    public Dictionary<string, object> ExtensionData { get; set; }
}

前に示した JSON をこのサンプル型に逆シリアル化すると、余分なデータが ExtensionData プロパティのキーと値のペアになります。When you deserialize the JSON shown earlier into this sample type, the extra data becomes key-value pairs of the ExtensionData property:

プロパティProperty [値]Value メモNotes
DateDate 8/1/2019 12:00:00 AM -07:008/1/2019 12:00:00 AM -07:00
TemperatureCelsiusTemperatureCelsius 00 大文字と小文字の区別が一致しないため (JSON では temperatureCelsius)、プロパティは設定されません。Case-sensitive mismatch (temperatureCelsius in the JSON), so the property isn't set.
まとめSummary ホットHot
ExtensionDataExtensionData temperatureCelsius:25temperatureCelsius: 25 大文字と小文字の区別が一致しなかったため、この JSON プロパティは余分で、ディクショナリ内のキーと値のペアになります。Since the case didn't match, this JSON property is an extra and becomes a key-value pair in the dictionary.
DatesAvailable:DatesAvailable:
8/1/2019 12:00:00 AM -07:008/1/2019 12:00:00 AM -07:00
8/2/2019 12:00:00 AM -07:008/2/2019 12:00:00 AM -07:00
JSON からの余分なプロパティは、値オブジェクトとしての配列を持つキーと値のペアになります。Extra property from the JSON becomes a key-value pair, with an array as the value object.
SummaryWords:SummaryWords:
CoolCool
強風Windy
HumidHumid
JSON からの余分なプロパティは、値オブジェクトとしての配列を持つキーと値のペアになります。Extra property from the JSON becomes a key-value pair, with an array as the value object.

ターゲット オブジェクトがシリアル化されると、拡張データのキーと値のペアは、受信 JSON 内にあった場合と同様に JSON プロパティになります。When the target object is serialized, the extension data key value pairs become JSON properties just as they were in the incoming JSON:

{
  "Date": "2019-08-01T00:00:00-07:00",
  "TemperatureCelsius": 0,
  "Summary": "Hot",
  "temperatureCelsius": 25,
  "DatesAvailable": [
    "2019-08-01T00:00:00-07:00",
    "2019-08-02T00:00:00-07:00"
  ],
  "SummaryWords": [
    "Cool",
    "Windy",
    "Humid"
  ]
}

JSON には ExtensionData プロパティ名が表示されないことに注意してください。Notice that the ExtensionData property name doesn't appear in the JSON. この動作により、JSON は、逆シリアル化されない余分なデータを失うことなく、ラウンド トリップを行うことができます。This behavior lets the JSON make a round trip without losing any extra data that otherwise wouldn't be deserialized.

逆シリアル化時に null を無視するIgnore null when deserializing

既定では、JSON 内のプロパティが null の場合、ターゲット オブジェクト内の対応するプロパティは null に設定されます。By default, if a property in JSON is null, the corresponding property in the target object is set to null. 場合によっては、ターゲット プロパティに既定値が設定されていて、既定値を null 値でオーバーライドしたくないことがあります。In some scenarios, the target property might have a default value, and you don't want a null value to override the default.

たとえば、次のコードがターゲット オブジェクトを表しているとします。For example, suppose the following code represents your target object:

public class WeatherForecastWithDefault
{
    public WeatherForecastWithDefault()
    {
        Date = DateTimeOffset.Parse("2001-01-01");
        Summary = "No summary";
    }
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string Summary { get; set; }
}

次の JSON が逆シリアル化されるとします。And suppose the following JSON is deserialized:

{
  "Date": "2019-08-01T00:00:00-07:00",
  "TemperatureCelsius": 25,
  "Summary": null
}

逆シリアル化後、WeatherForecastWithDefault オブジェクトの Summary プロパティは null になります。After deserialization, the Summary property of the WeatherForecastWithDefault object is null.

この動作を変更するには、次の例に示すように、JsonSerializerOptions.IgnoreNullValuestrue に設定します。To change this behavior, set JsonSerializerOptions.IgnoreNullValues to true, as shown in the following example:

var options = new JsonSerializerOptions
{
    IgnoreNullValues = true
};
weatherForecast = JsonSerializer.Deserialize<WeatherForecastWithDefault>(jsonString, options);

このオプションを使用すると、逆シリアル化後に、WeatherForecastWithDefault オブジェクトの Summary プロパティが既定値の "No summary" になります。With this option, the Summary property of the WeatherForecastWithDefault object is the default value "No summary" after deserialization.

JSON 内の Null 値は、有効な場合にのみ無視されます。Null values in the JSON are ignored only if they are valid. null 非許容の値の型に対して Null 値を指定すると、例外が発生します。Null values for non-nullable value types cause exceptions.

Utf8JsonReader、Utf8JsonWriter、JsonDocumentUtf8JsonReader, Utf8JsonWriter, and JsonDocument

System.Text.Json.Utf8JsonReader は、UTF-8 でエンコードされた JSON テキスト用の、ハイパフォーマンス、低割り当て、順方向専用のリーダーです。ReadOnlySpan<byte> または ReadOnlySequence<byte> から読み取られます。System.Text.Json.Utf8JsonReader is a high-performance, low allocation, forward-only reader for UTF-8 encoded JSON text, read from a ReadOnlySpan<byte> or ReadOnlySequence<byte>. Utf8JsonReader は低レベルの型であり、カスタム パーサーとデシリアライザーを構築するために使用できます。The Utf8JsonReader is a low-level type that can be used to build custom parsers and deserializers. JsonSerializer.Deserialize メソッドでは、内部で Utf8JsonReader が使用されます。The JsonSerializer.Deserialize method uses Utf8JsonReader under the covers.

System.Text.Json.Utf8JsonWriter は、StringInt32DateTime のような一般的な .NET 型から UTF-8 でエンコードされた JSON テキストを書き込むための、ハイパフォーマンスな方法です。System.Text.Json.Utf8JsonWriter is a high-performance way to write UTF-8 encoded JSON text from common .NET types like String, Int32, and DateTime. ライターは低レベルの型であり、カスタム シリアライザーを構築するために使用できます。The writer is a low-level type that can be used to build custom serializers. JsonSerializer.Serialize メソッドでは、内部で Utf8JsonWriter が使用されます。The JsonSerializer.Serialize method uses Utf8JsonWriter under the covers.

System.Text.Json.JsonDocument では、Utf8JsonReader を使用して、読み取り専用のドキュメント オブジェクト モデル (DOM) を構築する機能が提供されます。System.Text.Json.JsonDocument provides the ability to build a read-only Document Object Model (DOM) by using Utf8JsonReader. DOM では、JSON ペイロード内のデータへのランダム アクセスが提供されます。The DOM provides random access to data in a JSON payload. ペイロードを構成する JSON 要素には、JsonElement 型を使用してアクセスできます。The JSON elements that compose the payload can be accessed via the JsonElement type. JsonElement 型では、配列とオブジェクト列挙子と共に、JSON テキストを一般的な .NET 型に変換する API が提供されます。The JsonElement type provides array and object enumerators along with APIs to convert JSON text to common .NET types. JsonDocument では RootElement プロパティが公開されます。JsonDocument exposes a RootElement property.

以下のセクションでは、これらのツールを使用して JSON の読み取りと書き込みを行う方法を示します。The following sections show how to use these tools for reading and writing JSON.

JsonDocument を使用してデータにアクセスするUse JsonDocument for access to data

次の例は、JsonDocument クラスを使用して JSON 文字列内のデータにランダム アクセスする方法を示しています。The following example shows how to use the JsonDocument class for random access to data in a JSON string:

double sum = 0;
int count = 0;

using (JsonDocument document = JsonDocument.Parse(jsonString))
{
    JsonElement root = document.RootElement;
    JsonElement studentsElement = root.GetProperty("Students");
    foreach (JsonElement student in studentsElement.EnumerateArray())
    {
        if (student.TryGetProperty("Grade", out JsonElement gradeElement))
        {
            sum += gradeElement.GetDouble();
        }
        else
        {
            sum += 70;
        }
        count++;
    }
}

double average = sum / count;
Console.WriteLine($"Average grade : {average}");

上記のコードでは次の操作が行われます。The preceding code:

  • 分析する JSON が jsonString という名前の文字列に含まれていると想定します。Assumes the JSON to analyze is in a string named jsonString.

  • Grade プロパティを持つ Students 配列内のオブジェクトの平均グレードを計算します。Calculates an average grade for objects in a Students array that have a Grade property.

  • グレードのない学生には既定のグレード 70 を割り当てます。Assigns a default grade of 70 for students who don't have a grade.

  • 反復するたびに count 変数をインクリメントして学生をカウントします。Counts students by incrementing a count variable with each iteration. 別の方法として、次の例に示すように GetArrayLength を呼び出すこともできます。An alternative is to call GetArrayLength, as shown in the following example:

    double sum = 0;
    int count = 0;
    
    using (JsonDocument document = JsonDocument.Parse(jsonString))
    {
        JsonElement root = document.RootElement;
        JsonElement studentsElement = root.GetProperty("Students");
    
        count = studentsElement.GetArrayLength();
    
        foreach (JsonElement student in studentsElement.EnumerateArray())
        {
            if (student.TryGetProperty("Grade", out JsonElement gradeElement))
            {
                sum += gradeElement.GetDouble();
            }
            else
            {
                sum += 70;
            }
        }
    }
    
    double average = sum / count;
    Console.WriteLine($"Average grade : {average}");
    

このコードで処理される JSON の例を次に示します。Here's an example of the JSON that this code processes:

{
  "Class Name": "Science",
  "Teacher\u0027s Name": "Jane",
  "Semester": "2019-01-01",
  "Students": [
    {
      "Name": "John",
      "Grade": 94.3
    },
    {
      "Name": "James",
      "Grade": 81.0
    },
    {
      "Name": "Julia",
      "Grade": 91.9
    },
    {
      "Name": "Jessica",
      "Grade": 72.4
    },
    {
      "Name": "Johnathan"
    }
  ],
  "Final": true
}

JsonDocument を使用して JSON を書き込むUse JsonDocument to write JSON

次の例では、JsonDocument から JSON を書き込む方法を示します。The following example shows how to write JSON from a JsonDocument:

string jsonString = File.ReadAllText(inputFileName);

var writerOptions = new JsonWriterOptions
{
    Indented = true
};

var documentOptions = new JsonDocumentOptions
{
    CommentHandling = JsonCommentHandling.Skip
};

using FileStream fs = File.Create(outputFileName);
using var writer = new Utf8JsonWriter(fs, options: writerOptions);
using JsonDocument document = JsonDocument.Parse(jsonString, documentOptions);

JsonElement root = document.RootElement;

if (root.ValueKind == JsonValueKind.Object)
{
    writer.WriteStartObject();
}
else
{
    return;
}

foreach (JsonProperty property in root.EnumerateObject())
{
    property.WriteTo(writer);
}

writer.WriteEndObject();

writer.Flush();

上記のコードでは次の操作が行われます。The preceding code:

  • JSON ファイルを読み取り、データを JsonDocument に読み込み、書式設定された (整形された) JSON をファイルに書き込みます。Reads a JSON file, loads the data into a JsonDocument, and writes formatted (pretty-printed) JSON to a file.
  • JsonDocumentOptions を使用して、入力 JSON 内でコメントは許可されるが無視されることを指定します。Uses JsonDocumentOptions to specify that comments in the input JSON are allowed but ignored.
  • 完了したら、ライターに対して Flush を呼び出します。When finished, calls Flush on the writer. 別の方法として、破棄されたときにライターを自動フラッシュすることもできます。An alternative is to let the writer autoflush when it's disposed.

コード例によって処理される JSON 入力の例を次に示します。Here's an example of JSON input to be processed by the example code:

{"Class Name": "Science","Teacher's Name": "Jane","Semester": "2019-01-01","Students": [{"Name": "John","Grade": 94.3},{"Name": "James","Grade": 81.0},{"Name": "Julia","Grade": 91.9},{"Name": "Jessica","Grade": 72.4},{"Name": "Johnathan"}],"Final": true}

その結果は、次のような整形された JSON 出力になります。The result is the following pretty-printed JSON output:

{
  "Class Name": "Science",
  "Teacher\u0027s Name": "Jane",
  "Semester": "2019-01-01",
  "Students": [
    {
      "Name": "John",
      "Grade": 94.3
    },
    {
      "Name": "James",
      "Grade": 81.0
    },
    {
      "Name": "Julia",
      "Grade": 91.9
    },
    {
      "Name": "Jessica",
      "Grade": 72.4
    },
    {
      "Name": "Johnathan"
    }
  ],
  "Final": true
}

Utf8JsonWriter を使用するUse Utf8JsonWriter

Utf8JsonWriter クラスを使用する方法を示す例を次に示します。The following example shows how to use the Utf8JsonWriter class:

var options = new JsonWriterOptions
{
    Indented = true
};

using (var stream = new MemoryStream())
{
    using (var writer = new Utf8JsonWriter(stream, options))
    {
        writer.WriteStartObject();
        writer.WriteString("date", DateTimeOffset.UtcNow);
        writer.WriteNumber("temp", 42);
        writer.WriteEndObject();
    }

    string json = Encoding.UTF8.GetString(stream.ToArray());
    Console.WriteLine(json);
}

Utf8JsonReader を使用するUse Utf8JsonReader

Utf8JsonReader クラスを使用する方法を示す例を次に示します。The following example shows how to use the Utf8JsonReader class:

var options = new JsonReaderOptions
{
    AllowTrailingCommas = true,
    CommentHandling = JsonCommentHandling.Skip
};
Utf8JsonReader reader = new Utf8JsonReader(jsonUtf8Bytes, options);

while (reader.Read())
{
    Console.Write(reader.TokenType);

    switch (reader.TokenType)
    {
        case JsonTokenType.PropertyName:
        case JsonTokenType.String:
            {
                string text = reader.GetString();
                Console.Write(" ");
                Console.Write(text);
                break;
            }

        case JsonTokenType.Number:
            {
                int intValue = reader.GetInt32();
                Console.Write(" ");
                Console.Write(intValue);
                break;
            }

            // Other token types elided for brevity
    }
    Console.WriteLine();
}

上記のコードでは、jsonUtf8 変数が、UTF-8 としてエンコードされた有効な JSON を含むバイト配列であることを想定しています。The preceding code assumes that the jsonUtf8 variable is a byte array that contains valid JSON, encoded as UTF-8.

Utf8JsonReader を使用してデータをフィルター処理するFilter data using Utf8JsonReader

次の例は、ファイルを同期的に読み取り、値を検索する方法を示しています。The following example shows how to read a file synchronously and search for a value:

using System;
using System.IO;
using System.Text;
using System.Text.Json;

namespace SystemTextJsonSamples
{
    public class Utf8ReaderFromFile
    {
        private static readonly byte[] s_nameUtf8 = Encoding.UTF8.GetBytes("name");
        private static ReadOnlySpan<byte> Utf8Bom => new byte[] { 0xEF, 0xBB, 0xBF };
        public static void Run()
        {
            // ReadAllBytes if the file encoding is UTF-8:
            string fileName = "UniversitiesUtf8.json";
            ReadOnlySpan<byte> jsonReadOnlySpan = File.ReadAllBytes(fileName);

            // Read past the UTF-8 BOM bytes if a BOM exists.
            if (jsonReadOnlySpan.StartsWith(Utf8Bom))
            {
                jsonReadOnlySpan = jsonReadOnlySpan.Slice(Utf8Bom.Length);
            }

            // Or read as UTF-16 and transcode to UTF-8 to convert to a ReadOnlySpan<byte>
            //string fileName = "Universities.json";
            //string jsonString = File.ReadAllText(fileName);
            //ReadOnlySpan<byte> jsonReadOnlySpan = Encoding.UTF8.GetBytes(jsonString);


            int count = 0;
            int total = 0;

            var reader = new Utf8JsonReader(jsonReadOnlySpan);

            while (reader.Read())
            {
                JsonTokenType tokenType = reader.TokenType;

                switch (tokenType)
                {
                    case JsonTokenType.StartObject:
                        total++;
                        break;
                    case JsonTokenType.PropertyName:
                        if (reader.ValueTextEquals(s_nameUtf8))
                        {
                            // Assume valid JSON, known schema
                            reader.Read();
                            if (reader.GetString().EndsWith("University"))
                            {
                                count++;
                            }
                        }
                        break;
                }
            }
            Console.WriteLine($"{count} out of {total} have names that end with 'University'");
        }
    }
}

上記のコードでは次の操作が行われます。The preceding code:

  • JSON にオブジェクトの配列が含まれ、各オブジェクトに文字列型の "name" プロパティが含まれている可能性があると想定します。Assumes the JSON contains an array of objects and each object may contain a "name" property of type string.

  • オブジェクトと "University" で終わる "name" プロパティ値をカウントします。Counts objects and "name" property values that end with "University".

  • ファイルが UTF-16 としてエンコードされ、UTF-8 にトランスコードされるものと想定します。Assumes the file is encoded as UTF-16 and transcodes it into UTF-8. UTF-8 としてエンコードされたファイルは、次のコードを使用して、ReadOnlySpan<byte> に直接読み取ることができます。A file encoded as UTF-8 can be read directly into a ReadOnlySpan<byte>, by using the following code:

    ReadOnlySpan<byte> jsonReadOnlySpan = File.ReadAllBytes(fileName);
    

    リーダーではテキストが想定されるため、ファイルに UTF-8 バイト オーダー マーク (BOM) が含まれている場合は、バイトを Utf8JsonReader に渡す前にそれを削除します。If the file contains a UTF-8 byte order mark (BOM), remove it before passing the bytes to the Utf8JsonReader, since the reader expects text. そうしないと、BOM は無効な JSON と見なされ、リーダーによって例外がスローされます。Otherwise, the BOM is considered invalid JSON, and the reader throws an exception.

上記のコードで読み取ることができる JSON のサンプルを次に示します。Here's a JSON sample that the preceding code can read. 結果として生成される概要メッセージは、"2 out of 4 have names that end with 'University'" です。The resulting summary message is "2 out of 4 have names that end with 'University'":

[
  {
    "web_pages": [ "https://contoso.edu/" ],
    "alpha_two_code": "US",
    "state-province": null,
    "country": "United States",
    "domains": [ "contoso.edu" ],
    "name": "Contoso Community College"
  },
  {
    "web_pages": [ "http://fabrikam.edu/" ],
    "alpha_two_code": "US",
    "state-province": null,
    "country": "United States",
    "domains": [ "fabrikam.edu" ],
    "name": "Fabrikam Community College"
  },
  {
    "web_pages": [ "http://www.contosouniversity.edu/" ],
    "alpha_two_code": "US",
    "state-province": null,
    "country": "United States",
    "domains": [ "contosouniversity.edu" ],
    "name": "Contoso University"
  },
  {
    "web_pages": [ "http://www.fabrikamuniversity.edu/" ],
    "alpha_two_code": "US",
    "state-province": null,
    "country": "United States",
    "domains": [ "fabrikamuniversity.edu" ],
    "name": "Fabrikam University"
  }
]

Utf8JsonReader を使用してストリームから読み取るRead from a stream using Utf8JsonReader

大きなファイル (ギガバイト以上のサイズなど) を読み取る場合、一度にファイル全体をメモリに読み込む必要を回避することができます。When reading a large file (a gigabyte or more in size, for example), you might want to avoid having to load the entire file into memory at once. このシナリオでは、FileStream を使用できます。For this scenario, you can use a FileStream.

Utf8JsonReader を使用してストリームから読み取る場合、次の規則が適用されます。When using the Utf8JsonReader to read from a stream, the following rules apply:

  • 部分的な JSON ペイロードを含むバッファーは、リーダーが処理を進めることができるように、少なくともその中で最大の JSON トークンと同じ大きさにする必要があります。The buffer containing the partial JSON payload must be at least as big as the largest JSON token within it so that the reader can make forward progress.
  • バッファーは、少なくとも JSON 内の空白の最大シーケンスと同じ大きさである必要があります。The buffer must be at least as big as the largest sequence of white space within the JSON.
  • リーダーでは、JSON ペイロード内の次の TokenType が完全に読み取られるまで、読み取られたデータが追跡されません。The reader doesn't keep track of the data it has read until it completely reads the next TokenType in the JSON payload. そのため、バッファー内にバイトが残っている場合は、再びリーダーに渡す必要があります。So when there are bytes left over in the buffer, you have to pass them to the reader again. BytesConsumed を使用して、残っているバイト数を確認できます。You can use BytesConsumed to determine how many bytes are left over.

次のコードは、ストリームから読み取る方法を示しています。The following code illustrates how to read from a stream. この例は、MemoryStream を示しています。The example shows a MemoryStream. 同様のコードが FileStream で機能しますが、開始時に UTF-8 BOM が FileStream に含まれている場合を除きます。Similar code will work with a FileStream, except when the FileStream contains a UTF-8 BOM at the start. その場合は、残りのバイトを Utf8JsonReader に渡す前に、バッファーからこれらの 3 バイトを取り除く必要があります。In that case, you need to strip those three bytes from the buffer before passing the remaining bytes to the Utf8JsonReader. そうしないと、BOM は JSON の有効な部分と見なされないため、リーダーによって例外がスローされます。Otherwise the reader would throw an exception, since the BOM is not considered a valid part of the JSON.

このサンプル コードでは、4 KB のバッファーから開始し、サイズが完全な JSON トークンに対応するのに十分な大きさではないことが判明するたびにバッファー サイズを 2 倍にします。これは、リーダーが JSON ペイロードの処理を進めるために必要です。The sample code starts with a 4KB buffer and doubles the buffer size each time it finds that the size is not big enough to fit a complete JSON token, which is required for the reader to make forward progress on the JSON payload. スニペットに用意されている JSON サンプルでは、非常に小さい初期バッファー サイズ (たとえば、10 バイト) を設定した場合にのみ、バッファー サイズが増加します。The JSON sample provided in the snippet triggers a buffer size increase only if you set a very small initial buffer size, for example, 10 bytes. 初期バッファー サイズを 10 に設定すると、Console.WriteLine ステートメントによって、バッファー サイズの増加の原因と影響が示されます。If you set the initial buffer size to 10, the Console.WriteLine statements illustrate the cause and effect of buffer size increases. 4 KB の初期バッファー サイズで、サンプルの JSON 全体が各 Console.WriteLine によって表示され、バッファー サイズを増やす必要はありません。At the 4KB initial buffer size, the entire sample JSON is shown by each Console.WriteLine, and the buffer size never has to be increased.

using System;
using System.IO;
using System.Text;
using System.Text.Json;

namespace SystemTextJsonSamples
{
    public class Utf8ReaderPartialRead
    {
        public static void Run()
        {
            var jsonString = @"{
                ""Date"": ""2019-08-01T00:00:00-07:00"",
                ""Temperature"": 25,
                ""TemperatureRanges"": {
                    ""Cold"": { ""High"": 20, ""Low"": -10 },
                    ""Hot"": { ""High"": 60, ""Low"": 20 }
                },
                ""Summary"": ""Hot"",
            }";

            byte[] bytes = Encoding.UTF8.GetBytes(jsonString);
            var stream = new MemoryStream(bytes);

            var buffer = new byte[4096];

            // Fill the buffer.
            // For this snippet, we're assuming the stream is open and has data.
            // If it might be closed or empty, check if the return value is 0.
            stream.Read(buffer);

            var reader = new Utf8JsonReader(buffer, isFinalBlock: false, state: default);
            Console.WriteLine($"String in buffer is: {Encoding.UTF8.GetString(buffer)}");

            // Search for "Summary" property name
            while (reader.TokenType != JsonTokenType.PropertyName || !reader.ValueTextEquals("Summary"))
            {
                if (!reader.Read())
                {
                    // Not enough of the JSON is in the buffer to complete a read.
                    GetMoreBytesFromStream(stream, ref buffer, ref reader);
                }
            }

            // Found the "Summary" property name.
            Console.WriteLine($"String in buffer is: {Encoding.UTF8.GetString(buffer)}");
            while (!reader.Read())
            {
                // Not enough of the JSON is in the buffer to complete a read.
                GetMoreBytesFromStream(stream, ref buffer, ref reader);
            }
            // Display value of Summary property, that is, "Hot".
            Console.WriteLine($"Got property value: {reader.GetString()}");
        }

        private static void GetMoreBytesFromStream(MemoryStream stream, ref byte[] buffer, ref Utf8JsonReader reader)
        {
            int bytesRead;
            if (reader.BytesConsumed < buffer.Length)
            {
                ReadOnlySpan<byte> leftover = buffer.AsSpan((int)reader.BytesConsumed);

                if (leftover.Length == buffer.Length)
                {
                    Array.Resize(ref buffer, buffer.Length * 2);
                    Console.WriteLine($"Increased buffer size to {buffer.Length}");
                }

                leftover.CopyTo(buffer);
                bytesRead = stream.Read(buffer.AsSpan(leftover.Length));
            }
            else
            {
                bytesRead = stream.Read(buffer);
            }
            Console.WriteLine($"String in buffer is: {Encoding.UTF8.GetString(buffer)}");
            reader = new Utf8JsonReader(buffer, isFinalBlock: bytesRead == 0, reader.CurrentState);
        }
    }
}

前の例では、バッファーをどの大きさまで拡大できるかに対して無制限を設定しています。The preceding example sets no limit to how big the buffer can grow. トークン サイズが大きすぎる場合、コードは OutOfMemoryException 例外で失敗する可能性があります。If the token size is too large, the code could fail with an OutOfMemoryException exception. これは、JSON にサイズが約 1 GB 以上のトークンが含まれている場合に発生する可能性があります。1 GB のサイズを 2 倍にすると、サイズが大きすぎて int32 バッファーに入り切らないためです。This can happen if the JSON contains a token that is around 1 GB or more in size, because doubling the 1 GB size results in a size that is too large to fit into an int32 buffer.

その他の技術情報Additional resources