如何在 System.Text.Json 中使用 JSON 文档对象模型
本文介绍如何使用 JSON 文档对象模型 (DOM) 对 JSON 有效负载中的数据进行随机访问。
JSON DOM 选项
在以下情况中,可以不使用 JsonSerializer 进行反序列化,而是使用 DOM:
- 没有要反序列化到的类型。
- 收到的 JSON 没有固定架构,并且必须检查了解它包含哪些内容。
System.Text.Json
提供了两种方法来生成 JSON DOM:
通过 JsonDocument,可使用
Utf8JsonReader
生成只读 DOM。 可以通过 JsonElement 类型访问构成有效负载的 JSON 元素。JsonElement
类型提供数组和对象枚举器,以及用于将 JSON 文本转换为常见 .NET 类型的 API。JsonDocument
公开了 RootElement 属性。 有关详细信息,请参阅本文后面的使用 JsonDocument。通过 JsonNode 以及 System.Text.Json.Nodes 中派生自它的类,可创建可变的 DOM。 可通过 JsonNode、JsonObject、JsonArray、JsonValue 和 JsonElement 类型访问构成有效负载的 JSON 元素。 有关详细信息,请参阅本文后面的使用
JsonNode
。
在 JsonDocument
和 JsonNode
之间进行选择时,请考虑以下因素:
- 创建
JsonNode
DOM 后,可更改它。JsonDocument
DOM 是不可变的。 - 通过
JsonDocument
DOM 可更快地访问其数据。
使用 JsonNode
以下示例演示如何使用 JsonNode 以及 System.Text.Json.Nodes 命名空间中的其他类型来执行以下操作:
- 从 JSON 字符串创建 DOM
- 从 DOM 写入 JSON。
- 从 DOM 获取值、对象或数组。
using System.Text.Json;
using System.Text.Json.Nodes;
namespace JsonNodeFromStringExample;
public class Program
{
public static void Main()
{
string jsonString = """
{
"Date": "2019-08-01T00:00:00",
"Temperature": 25,
"Summary": "Hot",
"DatesAvailable": [
"2019-08-01T00:00:00",
"2019-08-02T00:00:00"
],
"TemperatureRanges": {
"Cold": {
"High": 20,
"Low": -10
},
"Hot": {
"High": 60,
"Low": 20
}
}
}
""";
// Create a JsonNode DOM from a JSON string.
JsonNode forecastNode = JsonNode.Parse(jsonString)!;
// Write JSON from a JsonNode
var options = new JsonSerializerOptions { WriteIndented = true };
Console.WriteLine(forecastNode!.ToJsonString(options));
// output:
//{
// "Date": "2019-08-01T00:00:00",
// "Temperature": 25,
// "Summary": "Hot",
// "DatesAvailable": [
// "2019-08-01T00:00:00",
// "2019-08-02T00:00:00"
// ],
// "TemperatureRanges": {
// "Cold": {
// "High": 20,
// "Low": -10
// },
// "Hot": {
// "High": 60,
// "Low": 20
// }
// }
//}
// Get value from a JsonNode.
JsonNode temperatureNode = forecastNode!["Temperature"]!;
Console.WriteLine($"Type={temperatureNode.GetType()}");
Console.WriteLine($"JSON={temperatureNode.ToJsonString()}");
//output:
//Type = System.Text.Json.Nodes.JsonValue`1[System.Text.Json.JsonElement]
//JSON = 25
// Get a typed value from a JsonNode.
int temperatureInt = (int)forecastNode!["Temperature"]!;
Console.WriteLine($"Value={temperatureInt}");
//output:
//Value=25
// Get a typed value from a JsonNode by using GetValue<T>.
temperatureInt = forecastNode!["Temperature"]!.GetValue<int>();
Console.WriteLine($"TemperatureInt={temperatureInt}");
//output:
//Value=25
// Get a JSON object from a JsonNode.
JsonNode temperatureRanges = forecastNode!["TemperatureRanges"]!;
Console.WriteLine($"Type={temperatureRanges.GetType()}");
Console.WriteLine($"JSON={temperatureRanges.ToJsonString()}");
//output:
//Type = System.Text.Json.Nodes.JsonObject
//JSON = { "Cold":{ "High":20,"Low":-10},"Hot":{ "High":60,"Low":20} }
// Get a JSON array from a JsonNode.
JsonNode datesAvailable = forecastNode!["DatesAvailable"]!;
Console.WriteLine($"Type={datesAvailable.GetType()}");
Console.WriteLine($"JSON={datesAvailable.ToJsonString()}");
//output:
//datesAvailable Type = System.Text.Json.Nodes.JsonArray
//datesAvailable JSON =["2019-08-01T00:00:00", "2019-08-02T00:00:00"]
// Get an array element value from a JsonArray.
JsonNode firstDateAvailable = datesAvailable[0]!;
Console.WriteLine($"Type={firstDateAvailable.GetType()}");
Console.WriteLine($"JSON={firstDateAvailable.ToJsonString()}");
//output:
//Type = System.Text.Json.Nodes.JsonValue`1[System.Text.Json.JsonElement]
//JSON = "2019-08-01T00:00:00"
// Get a typed value by chaining references.
int coldHighTemperature = (int)forecastNode["TemperatureRanges"]!["Cold"]!["High"]!;
Console.WriteLine($"TemperatureRanges.Cold.High={coldHighTemperature}");
//output:
//TemperatureRanges.Cold.High = 20
// Parse a JSON array
var datesNode = JsonNode.Parse(@"[""2019-08-01T00:00:00"",""2019-08-02T00:00:00""]");
JsonNode firstDate = datesNode![0]!.GetValue<DateTime>();
Console.WriteLine($"firstDate={ firstDate}");
//output:
//firstDate = "2019-08-01T00:00:00"
}
}
使用对象初始值设定项创建 JsonNode DOM 并进行更改
以下示例介绍如何:
- 使用对象初始值设定项创建 DOM。
- 对 DOM 进行更改。
using System.Text.Json;
using System.Text.Json.Nodes;
namespace JsonNodeFromObjectExample;
public class Program
{
public static void Main()
{
// Create a new JsonObject using object initializers.
var forecastObject = new JsonObject
{
["Date"] = new DateTime(2019, 8, 1),
["Temperature"] = 25,
["Summary"] = "Hot",
["DatesAvailable"] = new JsonArray(
new DateTime(2019, 8, 1), new DateTime(2019, 8, 2)),
["TemperatureRanges"] = new JsonObject
{
["Cold"] = new JsonObject
{
["High"] = 20,
["Low"] = -10
}
},
["SummaryWords"] = new JsonArray("Cool", "Windy", "Humid")
};
// Add an object.
forecastObject!["TemperatureRanges"]!["Hot"] =
new JsonObject { ["High"] = 60, ["Low"] = 20 };
// Remove a property.
forecastObject.Remove("SummaryWords");
// Change the value of a property.
forecastObject["Date"] = new DateTime(2019, 8, 3);
var options = new JsonSerializerOptions { WriteIndented = true };
Console.WriteLine(forecastObject.ToJsonString(options));
//output:
//{
// "Date": "2019-08-03T00:00:00",
// "Temperature": 25,
// "Summary": "Hot",
// "DatesAvailable": [
// "2019-08-01T00:00:00",
// "2019-08-02T00:00:00"
// ],
// "TemperatureRanges": {
// "Cold": {
// "High": 20,
// "Low": -10
// },
// "Hot": {
// "High": 60,
// "Low": 20
// }
// }
//}
}
}
对 JSON 有效负载的子节进行反初始化
以下示例演示如何使用 JsonNode 导航到 JSON 树的子节,以及如何反序列化该子节中的单个值、自定义类型或数组。
using System.Text.Json;
using System.Text.Json.Nodes;
namespace JsonNodePOCOExample;
public class TemperatureRanges : Dictionary<string, HighLowTemps>
{
}
public class HighLowTemps
{
public int High { get; set; }
public int Low { get; set; }
}
public class Program
{
public static DateTime[]? DatesAvailable { get; set; }
public static void Main()
{
string jsonString = """
{
"Date": "2019-08-01T00:00:00",
"Temperature": 25,
"Summary": "Hot",
"DatesAvailable": [
"2019-08-01T00:00:00",
"2019-08-02T00:00:00"
],
"TemperatureRanges": {
"Cold": {
"High": 20,
"Low": -10
},
"Hot": {
"High": 60,
"Low": 20
}
}
}
""";
// Parse all of the JSON.
JsonNode forecastNode = JsonNode.Parse(jsonString)!;
// Get a single value
int hotHigh = forecastNode["TemperatureRanges"]!["Hot"]!["High"]!.GetValue<int>();
Console.WriteLine($"Hot.High={hotHigh}");
// output:
//Hot.High=60
// Get a subsection and deserialize it into a custom type.
JsonObject temperatureRangesObject = forecastNode!["TemperatureRanges"]!.AsObject();
using var stream = new MemoryStream();
using var writer = new Utf8JsonWriter(stream);
temperatureRangesObject.WriteTo(writer);
writer.Flush();
TemperatureRanges? temperatureRanges =
JsonSerializer.Deserialize<TemperatureRanges>(stream.ToArray());
Console.WriteLine($"Cold.Low={temperatureRanges!["Cold"].Low}, Hot.High={temperatureRanges["Hot"].High}");
// output:
//Cold.Low=-10, Hot.High=60
// Get a subsection and deserialize it into an array.
JsonArray datesAvailable = forecastNode!["DatesAvailable"]!.AsArray()!;
Console.WriteLine($"DatesAvailable[0]={datesAvailable[0]}");
// output:
//DatesAvailable[0]=8/1/2019 12:00:00 AM
}
}
JsonNode 平均等级示例
以下示例选择一个包含整数值的 JSON 数组,并计算平均值:
using System.Text.Json.Nodes;
namespace JsonNodeAverageGradeExample;
public class Program
{
public static void Main()
{
string jsonString = """
{
"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
}
""";
double sum = 0;
JsonNode document = JsonNode.Parse(jsonString)!;
JsonNode root = document.Root;
JsonArray studentsArray = root["Students"]!.AsArray();
int count = studentsArray.Count;
foreach (JsonNode? student in studentsArray)
{
if (student?["Grade"] is JsonNode gradeNode)
{
sum += (double)gradeNode;
}
else
{
sum += 70;
}
}
double average = sum / count;
Console.WriteLine($"Average grade : {average}");
}
}
// output:
//Average grade : 81.92
前面的代码:
- 对
Students
数组中具有Grade
属性的对象计算平均成绩。 - 为没有成绩的学生分配默认成绩 70。
- 从
JsonArray
的Count
属性获取学生人数。
带 JsonSerializerOptions
的 JsonNode
可以使用 JsonSerializer
对 JsonNode
的实例进行序列化和反序列化。 但是,如果使用采用 JsonSerializerOptions
的重载,则 options 实例仅用于获取自定义转换器。 不使用 options 实例的其他功能。 例如,如果将 JsonSerializerOptions.DefaultIgnoreCondition 设置为 WhenWritingNull,并且使用采用 JsonSerializerOptions
的重载来调用 JsonSerializer
,则不会忽略 NULL 属性。
相同的限制适用于采用 JsonSerializerOptions
参数的 JsonNode
方法:WriteTo(Utf8JsonWriter, JsonSerializerOptions) 和 ToJsonString(JsonSerializerOptions)。 这些 API 仅使用 JsonSerializerOptions
获取自定义转换器。
下面的示例演示了使用采用 JsonSerializerOptions
参数并对 JsonNode
实例进行序列化的方法的结果:
using System.Text;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
namespace JsonNodeWithJsonSerializerOptions;
public class Program
{
public static void Main()
{
Person person = new() { Name = "Nancy" };
// Default serialization - Address property included with null token.
// Output: {"Name":"Nancy","Address":null}
string personJsonWithNull = JsonSerializer.Serialize(person);
Console.WriteLine(personJsonWithNull);
// Serialize and ignore null properties - null Address property is omitted
// Output: {"Name":"Nancy"}
JsonSerializerOptions options = new()
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};
string personJsonWithoutNull = JsonSerializer.Serialize(person, options);
Console.WriteLine(personJsonWithoutNull);
// Ignore null properties doesn't work when serializing JsonNode instance
// by using JsonSerializer.
// Output: {"Name":"Nancy","Address":null}
JsonNode? personJsonNode = JsonSerializer.Deserialize<JsonNode>(personJsonWithNull);
personJsonWithNull = JsonSerializer.Serialize(personJsonNode, options);
Console.WriteLine(personJsonWithNull);
// Ignore null properties doesn't work when serializing JsonNode instance
// by using JsonNode.ToJsonString method.
// Output: {"Name":"Nancy","Address":null}
personJsonWithNull = personJsonNode!.ToJsonString(options);
Console.WriteLine(personJsonWithNull);
// Ignore null properties doesn't work when serializing JsonNode instance
// by using JsonNode.WriteTo method.
// Output: {"Name":"Nancy","Address":null}
using var stream = new MemoryStream();
using var writer = new Utf8JsonWriter(stream);
personJsonNode!.WriteTo(writer, options);
writer.Flush();
personJsonWithNull = Encoding.UTF8.GetString(stream.ToArray());
Console.WriteLine(personJsonWithNull);
}
}
public class Person
{
public string? Name { get; set; }
public string? Address { get; set; }
}
如果需要 JsonSerializerOptions
除自定义转换器之外的功能,请将 JsonSerializer
与强类型目标(如本示例中的 Person
类)而不是 JsonNode
结合使用。
操作属性顺序
JsonObject 是 JsonNode 有效负载中的一个元素,表示一个可变 JSON 对象。 尽管该类型作为一个 IDictionary<string, JsonNode>
建模,其中每个条目都是对象的一个属性,但它封装了一个隐式属性顺序。 但是,Insert(Int32, String, JsonNode) 和 RemoveAt(Int32) 等 API 可让你在特定索引处插入和删除项目,从而有效地将类型建模为有序字典。 这些 API 允许修改对象实例,从而直接影响属性顺序。
以下代码展示了一个将特定属性添加或移动到对象起始位置的示例。
var schema = (JsonObject)JsonSerializerOptions.Default.GetJsonSchemaAsNode(typeof(MyPoco));
JsonNode? idValue;
switch (schema.IndexOf("$id"))
{
// $id property missing.
case < 0:
idValue = (JsonNode)"https://example.com/schema";
schema.Insert(0, "$id", idValue);
break;
// $id property already at the start of the object.
case 0:
break;
// $id exists but not at the start of the object.
case int index:
idValue = schema[index];
schema.RemoveAt(index);
schema.Insert(0, "$id", idValue);
break;
}
比较 JsonNode
要比较两个 JsonNode
对象是否相等,包括它们的后代元素,请使用 JsonNode.DeepEquals(JsonNode, JsonNode) 方法。
使用 JsonDocument
下面的示例演示如何使用 JsonDocument 类来随机访问 JSON 字符串中的数据:
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}");
Dim sum As Double = 0
Dim count As Integer = 0
Using document As JsonDocument = JsonDocument.Parse(jsonString)
Dim root As JsonElement = document.RootElement
Dim studentsElement As JsonElement = root.GetProperty("Students")
For Each student As JsonElement In studentsElement.EnumerateArray()
Dim gradeElement As JsonElement = Nothing
If student.TryGetProperty("Grade", gradeElement) Then
sum += gradeElement.GetDouble()
Else
sum += 70
End If
count += 1
Next
End Using
Dim average As Double = sum / count
Console.WriteLine($"Average grade : {average}")
前面的代码:
- 假设要分析的 JSON 处于名为
jsonString
的字符串中。 - 对
Students
数组中具有Grade
属性的对象计算平均成绩。 - 为没有成绩的学生分配默认成绩 70。
- 在
using
语句中创建JsonDocument
实例,因为JsonDocument
会实现IDisposable
。 释放JsonDocument
实例后,你也无法在访问其所有的JsonElement
实例。 若要能够继续访问JsonElement
实例,请创建该实例的副本,然后再释放父JsonDocument
实例。 若要创建副本,请调用 JsonElement.Clone。 有关详细信息,请参阅 JsonDocument 是 IDisposable。
上述示例代码通过每次迭代递增 count
变量来计算学生人数。 一种替代方法是调用 GetArrayLength,如以下示例中所示:
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}");
Dim sum As Double = 0
Dim count As Integer = 0
Using document As JsonDocument = JsonDocument.Parse(jsonString)
Dim root As JsonElement = document.RootElement
Dim studentsElement As JsonElement = root.GetProperty("Students")
count = studentsElement.GetArrayLength()
For Each student As JsonElement In studentsElement.EnumerateArray()
Dim gradeElement As JsonElement = Nothing
If student.TryGetProperty("Grade", gradeElement) Then
sum += gradeElement.GetDouble()
Else
sum += 70
End If
Next
End Using
Dim average As Double = sum / count
Console.WriteLine($"Average grade : {average}")
下面是此代码处理的 JSON 示例:
{
"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
}
如需使用 JsonNode
而不是 JsonDocument
的类似示例,请参阅 JsonNode 平均等级示例。
如何搜索子元素的 JsonDocument 和 JsonElement
若要对 JsonElement
进行搜索,需要对属性进行线性搜索,因此速度相对较慢(例如在使用 TryGetProperty
时)。 System.Text.Json 旨在最大程度减少初始分析时间,而不是查找时间。 因此,在通过 JsonDocument
对象搜索时,请使用以下方法优化性能:
- 使用内置枚举器(EnumerateArray 和 EnumerateObject),而不是执行自己的索引或循环。
- 不要使用
RootElement
通过每个属性对整个JsonDocument
执行线性搜索。 而是基于 JSON 数据的已知结构对嵌套 JSON 对象进行搜索。 例如,前面的代码示例在Student
对象中查找Grade
属性,方法是循环访问Student
对象,并获取每个对象的Grade
值,而不是搜索所有Grade
对象来查找JsonElement
属性。 执行后者会导致不必要浏览相同数据。
比较 JsonElement
要比较两个 JsonElement
对象是否相等,包括它们的后代元素,请使用 JsonElement.DeepEquals(JsonElement, JsonElement) 方法。
JsonElement left = JsonDocument.Parse("10e-3").RootElement;
JsonElement right = JsonDocument.Parse("0.01").RootElement;
bool equal = JsonElement.DeepEquals(left, right);
Console.WriteLine(equal); // True.
使用 JsonDocument
编写 JSON
下面的示例演示如何通过 JsonDocument 写入 JSON:
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();
Dim jsonString As String = File.ReadAllText(inputFileName)
Dim writerOptions As JsonWriterOptions = New JsonWriterOptions With {
.Indented = True
}
Dim documentOptions As JsonDocumentOptions = New JsonDocumentOptions With {
.CommentHandling = JsonCommentHandling.Skip
}
Dim fs As FileStream = File.Create(outputFileName)
Dim writer As Utf8JsonWriter = New Utf8JsonWriter(fs, options:=writerOptions)
Dim document As JsonDocument = JsonDocument.Parse(jsonString, documentOptions)
Dim root As JsonElement = document.RootElement
If root.ValueKind = JsonValueKind.[Object] Then
writer.WriteStartObject()
Else
Return
End If
For Each [property] As JsonProperty In root.EnumerateObject()
[property].WriteTo(writer)
Next
writer.WriteEndObject()
writer.Flush()
前面的代码:
- 读取 JSON 文件,将数据加载到
JsonDocument
中,并将格式化(进行了优质打印的)JSON 写入文件。 - 使用 JsonDocumentOptions 可指定允许但会忽略输入 JSON 中的注释。
- 完成后,对编写器调用 Flush。 一种替代方法是让编写器在释放时自动刷新。
下面是要由示例代码处理的 JSON 输入的示例:
{"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 输出:
{
"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 为 IDisposable
JsonDocument
将内存中的数据视图生成到共用缓冲区中。 因此,JsonDocument
类型会实现 IDisposable
,需要在 using
块内使用。
如果要将生存期所有权和释放责任转移到调用方,则只需从 API 返回 JsonDocument
。 在大多数情况下,这不是必需的。 如果调用方需要处理整个 JSON 文档,则返回 RootElement 的 Clone,这是 JsonElement。 如果调用方需要处理 JSON 文档中的特定元素,则返回该 JsonElement 的 Clone。 如果在不进行 Clone
的情况下直接返回 RootElement
或子元素,则在释放拥有返回的 JsonElement
的 JsonDocument
之后,调用方将无法访问它。
下面是一个要求你进行 Clone
的示例:
public JsonElement LookAndLoad(JsonElement source)
{
string json = File.ReadAllText(source.GetProperty("fileName").GetString());
using (JsonDocument doc = JsonDocument.Parse(json))
{
return doc.RootElement.Clone();
}
}
前面的代码需要包含 fileName
属性的 JsonElement
。 它会打开 JSON 文件并创建一个 JsonDocument
。 该方法假设调用方要处理整个文档,因此会返回 RootElement
的 Clone
。
如果收到 JsonElement
并要返回子元素,则无需返回子元素的 Clone
。 调用方负责使传入的 JsonElement
所属的 JsonDocument
保持活动状态。 例如:
public JsonElement ReturnFileName(JsonElement source)
{
return source.GetProperty("fileName");
}
带 JsonSerializerOptions
的 JsonDocument
可以使用 JsonSerializer
对 JsonDocument
的实例进行序列化和反序列化。 但是,使用 JsonSerializer
读取和写入 JsonDocument
实例的实现是 JsonDocument.ParseValue(Utf8JsonReader) 和 JsonDocument.WriteTo(Utf8JsonWriter) 的包装器。 此包装器不会将任何 JsonSerializerOptions
(序列化程序功能)转发到 Utf8JsonReader
或 Utf8JsonWriter
。 例如,如果将 JsonSerializerOptions.DefaultIgnoreCondition 设置为 WhenWritingNull,并且使用采用 JsonSerializerOptions
的重载来调用 JsonSerializer
,则不会忽略 NULL 属性。
下面的示例演示了使用采用 JsonSerializerOptions
参数并对 JsonDocument
实例进行序列化的方法的结果:
using System.Text.Json;
using System.Text.Json.Serialization;
namespace JsonDocumentWithJsonSerializerOptions;
public class Program
{
public static void Main()
{
Person person = new() { Name = "Nancy" };
// Default serialization - Address property included with null token.
// Output: {"Name":"Nancy","Address":null}
string personJsonWithNull = JsonSerializer.Serialize(person);
Console.WriteLine(personJsonWithNull);
// Serialize and ignore null properties - null Address property is omitted
// Output: {"Name":"Nancy"}
JsonSerializerOptions options = new()
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};
string personJsonWithoutNull = JsonSerializer.Serialize(person, options);
Console.WriteLine(personJsonWithoutNull);
// Ignore null properties doesn't work when serializing JsonDocument instance
// by using JsonSerializer.
// Output: {"Name":"Nancy","Address":null}
JsonDocument? personJsonDocument = JsonSerializer.Deserialize<JsonDocument>(personJsonWithNull);
personJsonWithNull = JsonSerializer.Serialize(personJsonDocument, options);
Console.WriteLine(personJsonWithNull);
}
}
public class Person
{
public string? Name { get; set; }
public string? Address { get; set; }
}
如果需要 JsonSerializerOptions
的功能,请将 JsonSerializer
与强类型目标(如本示例中的 Person
类)而不是 JsonDocument
结合使用。