如何在 .NET 中对 JSON 进行序列化和反序列化(marshal 和取消封送)How to serialize and deserialize (marshal and unmarshal) JSON in .NET

本文介绍如何使用 System.Text.Json 命名空间在 JavaScript 对象表示法(JSON)之间进行序列化和反序列化。This article shows how to use the System.Text.Json namespace to serialize and deserialize to and from JavaScript Object Notation (JSON).

方向和示例代码直接使用库,而不是通过框架(如ASP.NET Core)使用。The directions and sample code use the library directly, not through a framework such as ASP.NET Core.

大多数序列化示例代码将 JsonSerializerOptions.WriteIndented 设置为 true JSON (对于人工可读性,为缩进和空格)。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.

命名空间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.Text.Json当前不支持 System.Runtime.Serialization 命名空间中的属性。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-8Serialize 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);

还提供了一个采用 Utf8JsonWriterSerialize 重载。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.
  • 用户定义的普通旧 CLR 对象(poco)User-defined Plain Old CLR Objects (POCOs).
  • 一维数组和交错数组(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 进行反序列化,请调用采用 Utf8JsonReaderReadOnlySpan<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.

序列化为格式化的 JSONSerialize to formatted JSON

若要整齐地打印 JSON 输出,请将 JsonSerializerOptions.WriteIndented 设置为 trueTo 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 属性名称使用 camel 大小写Use camel case for all JSON property names

若要对所有 JSON 属性名称使用 camel 大小写,请将 JsonSerializerOptions.PropertyNamingPolicy 设置为 JsonNamingPolicy.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
}

Camel 大小写属性命名策略:The camel case property naming policy:

  • 适用于序列化和反序列化。Applies to serialization and deserialization.
  • [JsonPropertyName] 特性重写。Is overridden by [JsonPropertyName] attributes. 这就是示例中的 JSON 属性名称 Wind 不是 camel 大小写的原因。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. 这就是示例中 Wind 的 JSON 属性名称不大写的原因。This is why the JSON property name Wind in the example is not upper case.

Camel 大小写字典密钥Camel case dictionary keys

如果要序列化的对象的属性为 Dictionary<string,TValue>类型,则 string 键可转换为 camel 大小写形式。If a property of an object to be serialized is of type Dictionary<string,TValue>, the string keys can be converted to camel case. 为此,请将 DictionaryKeyPolicy 设置为 JsonNamingPolicy.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);

使用名为 TemperatureRanges 的字典序列化具有键值对 "ColdMinTemp", 20 的对象,"HotMinTemp", 40 将导致 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
  }
}

字典键的 camel 大小写命名策略仅适用于序列化。The camel case naming policy for dictionary keys applies to serialization only. 如果对字典进行反序列化,即使为 DictionaryKeyPolicy指定 JsonNamingPolicy.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. 若要将枚举名称序列化为字符串,请使用 JsonStringEnumConverterTo 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
}

如果 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
}

下面的示例代码序列化枚举名称,而不是数值,并将名称转换为 camel 大小写格式: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

如果属性包含公共 getter 而不是公共 setter,则该属性为只读。A property is read-only if it contains a public getter but not a public setter. 若要排除所有只读属性,请将 JsonSerializerOptions.IgnoreReadOnlyProperties 设置为 true,如以下示例中所示: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:

PropertyProperty {2>值<2}Value
日期Date 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. 有关对反序列化的影响的信息,请参阅反序列化时忽略 nullFor 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

若要序列化一种或多种语言的字符集而不进行转义,请在创建 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.AllTo 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. 下面的示例仅序列化жарко的前两个字符: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 或信息泄露攻击的额外防御防护,如客户端和服务器 disagreeing 在字符集上可能导致的任何其他防护。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 解释结果负载时,才使用 unsafe 编码器。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-8For 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 类和一个派生类 WeatherForecastDerivedFor 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 方法的类型实参 WeatherForecastAnd 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 runtime:

    options = new JsonSerializerOptions
    {
        WriteIndented = true
    };
    jsonString = JsonSerializer.Serialize(weatherForecast, weatherForecast.GetType(), options);
    
  • 将要序列化的对象声明为 objectDeclare 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 类具有一个名为 PreviousForecast 的属性,该属性可以定义为类型 WeatherForecastobjectFor 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 输出不包括WindSpeedThe JSON output from serializing WeatherForecastWithPrevious doesn't include WindSpeed.
  • 序列化 WeatherForecastWithPreviousAsObject 的 JSON 输出包括WindSpeedThe 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>GetTypeThe following code example doesn't call Serialize<object> or GetType:

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

前面的代码正确地序列化 WeatherForecastWithPreviousAsObjectThe 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的实例时,只有 Tuesday 显示 WindSpeed 属性,因为 Tuesday 定义为 objectWhen 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.JsonFor 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.SkipTo allow comments in the JSON, set the JsonSerializerOptions.ReadCommentHandling property to JsonCommentHandling.Skip. 若要允许尾随逗号,请将 JsonSerializerOptions.AllowTrailingCommas 属性设置为 trueAnd 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.PropertyNameCaseInsensitive 设置为 trueTo change that behavior, set JsonSerializerOptions.PropertyNameCaseInsensitive to true:

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

下面是采用 camel 大小写属性名称的示例 JSON。Here's example JSON with camel case property names. 它可以反序列化为具有 Pascal 大小写属性名称的以下类型。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; }
}

句柄溢出 JSONHandle 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 反序列化为显示的类型,则 "DatesAvailable" 和 "SummaryWords" 属性不会有任何位置,并且将丢失。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:

PropertyProperty {2>值<2}Value 注释Notes
日期Date 8/1/2019 12:00:00 AM-07:008/1/2019 12:00:00 AM -07:00
TemperatureCelsiusTemperatureCelsius 00 区分大小写不匹配(temperatureCelsius 在 JSON 中),因此未设置属性。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:
Cool
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"
  ]
}

请注意,ExtensionData 属性名称不会出现在 JSON 中。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.

反序列化时忽略 nullIgnore 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. 在某些情况下,target 属性可能具有默认值,并且你不希望 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.IgnoreNullValues 设置为 true,如以下示例中所示: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 属性是默认值 "无摘要"。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 是一种高性能的方式,用于从常见的 .NET 类型(如 StringInt32DateTime)编写 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. 可以通过 JsonElement 类型访问构成有效负载的 JSON 元素。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 要分析的字符串中有一个名为 jsonStringAssumes the JSON to analyze is in a string named jsonString.

  • 计算 Students 数组中具有 Grade 属性的对象的平均评分。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 编写 JSONUse 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.
  • 完成后,将对编写器调用 FlushWhen finished, calls Flush on the writer. 一种替代方法是让编写人员在 autoflush 时进行处理。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}

结果如下所示: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
}

使用 Utf8JsonWriterUse 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);
}

使用 Utf8JsonReaderUse 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 变量是包含有效 JSON 的字节数组,编码为 UTF-8。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.

  • 计算以 "大学" 结尾的对象和 "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 个,共4个名称以 ' 大学 ' 结尾":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"
  }
]

其他资源Additional resources