Использование объектной модели документа JSON в System.Text.Json
В этой статье показано, как использовать объектную модель документа JSON (DOM) для случайного доступа к данным в полезных данных JSON.
Варианты JSON DOM
Работа с DOM является альтернативой десериализации с помощью JsonSerializer :
- У вас нет типа для десериализации.
- Полученный код JSON не имеет фиксированной схемы и должен быть проверен, чтобы узнать, что он содержит.
System.Text.Json
предоставляет два способа создания DOM JSON:
JsonDocument предоставляет возможность создания DOM только для чтения с помощью
Utf8JsonReader
. Доступ к элементам JSON, составляющим полезные данные, можно получить с помощью типа JsonElement. ТипJsonElement
предоставляет перечислители массивов и объектов вместе с API-интерфейсами для преобразования текста JSON в стандартные типы .NET.JsonDocument
предоставляет свойство RootElement. Дополнительные сведения см. в разделе "Использование JsonDocument " далее в этой статье.JsonNode и классы, производные от него в System.Text.Json.Nodes пространстве имен, обеспечивают возможность создания мутируемой модели DOM. Доступ к элементам JSON, составляющим полезные данные, можно получить через JsonNodeJsonObjectтипы , и JsonArrayJsonValueJsonElement типы. Дополнительные сведения см
JsonNode
. далее в этой статье.
При выборе между JsonDocument
ими JsonNode
следует учитывать следующие факторы:
JsonNode
DOM можно изменить после его создания.JsonDocument
DOM неизменяем.JsonDocument
DOM обеспечивает быстрый доступ к своим данным.
Использование JsonNode
В следующем примере показано, как использовать JsonNode и другие типы в System.Text.Json.Nodes пространстве имен:
- Создание DOM из строки JSON
- Запись JSON из DOM.
- Получение значения, объекта или массива из 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"
}
}
Создание DOM JsonNode с инициализаторами объектов и внесение изменений
В приведенном ниже примере показано, как выполнить следующие задачи.
- Создайте 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 для учащихся, у которых нет оценки.
- Возвращает число учащихся из
Count
свойстваJsonArray
.
JsonNode
с JsonSerializerOptions
Можно использовать JsonSerializer
для сериализации и десериализации экземпляра JsonNode
. Однако при использовании перегрузки, которая принимает JsonSerializerOptions
, экземпляр параметров используется только для получения пользовательских преобразователей. Другие функции экземпляра параметров не используются. Например, если задано JsonSerializerOptions.DefaultIgnoreCondition WhenWritingNull значение и вызов JsonSerializer
с перегрузкой, которая принимает JsonSerializerOptions
, свойства NULL не будут игнорироваться.
То же ограничение применяется к JsonNode
методам, которые принимают JsonSerializerOptions
параметр: 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>
объект, где каждая запись является свойством объекта, она инкапсулирует неявный порядок свойств. Однако API, такие как Insert(Int32, String, JsonNode) и RemoveAt(Int32) эффективно моделировать тип как упорядоченный словарь, позволяя вставлять и удалять элементы по определенному индексу. Эти 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;
}
Сравнение JsonNodes
Чтобы сравнить два 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 для учащихся, у которых нет оценки.
JsonDocument
Создает экземпляр в инструкцииusing
, так как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) вместо создания собственных индексов или циклов.
- Не выполняйте последовательный поиск по всему
JsonDocument
в каждом свойстве с помощьюRootElement
. Вместо этого выполните поиск по вложенным объектам JSON на основе известной структуры данных JSON. Например, предыдущие примеры кода ищутGrade
свойство вStudent
объектах, циклируяStudent
объекты и получая значениеGrade
для каждого, а не выполняя поиск по всемJsonElement
объектам, которые ищутGrade
свойства. Выполнение последнего приведет к ненужным передачам одних и того же данных.
Сравнение JsonElements
Чтобы сравнить два 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
В следующем примере показано, как записать JSON код из 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();
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
блока.
Возвращайте JsonDocument
из API только в том случае, если хотите передать владение временем существования и ответственность вызывающему объекту. В большинстве случаев это необязательно. Если вызывающему объекту необходимо работать со всем документом JSON, возвращайте Clone RootElement, то есть JsonElement. Если вызывающему объекту необходимо работать с определенным элементом в документе JSON, возвращайте Clone этого JsonElement. Если вы возвращаете RootElement
или вложенный элемент напрямую, не выполняя Clone
, вызывающий объект не сможет получить доступ к возвращаемому объекту 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();
}
}
Приведенный выше код ждет JsonElement
, содержащий свойство fileName
. Он открывает JSON-файл и создает JsonDocument
. Метод предполагает, что вызывающий объект хочет работать со всем документом, поэтому он возвращает Clone
RootElement
.
Если вы получаете JsonElement
и возвращаете вложенный элемент, нет необходимости возвращать Clone
вложенного элемента. Вызывающий объект отвечает за поддержание активности JsonDocument
, которому принадлежит переданный JsonElement
. Например:
public JsonElement ReturnFileName(JsonElement source)
{
return source.GetProperty("fileName");
}
JsonDocument
с JsonSerializerOptions
Можно использовать JsonSerializer
для сериализации и десериализации экземпляра JsonDocument
. Однако реализация для чтения и записи JsonDocument
экземпляров с помощью JsonSerializer
является оболочкой над JsonDocument.ParseValue(Utf8JsonReader) и JsonDocument.WriteTo(Utf8JsonWriter). Эта оболочка не перенаправит никакие JsonSerializerOptions
(функции сериализатора) в Utf8JsonReader
или Utf8JsonWriter
. Например, если задано JsonSerializerOptions.DefaultIgnoreCondition WhenWritingNull значение и вызов JsonSerializer
с перегрузкой, которая принимает JsonSerializerOptions
, свойства 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
.