Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Неизменяемый тип предотвращает изменение значений свойств или полей объекта после его создания. Тип может быть записью, не имеет открытых свойств или полей, имеет свойства только для чтения или имеет свойства с закрытыми или только инициализаторами. System.String является примером неизменяемого типа. System.Text.Json предоставляет различные способы десериализации JSON в неизменяемые типы.
Параметризованные конструкторы
По умолчанию System.Text.Json использует общедоступный конструктор без параметров по умолчанию. Однако можно сказать, что он использует параметризованный конструктор, что позволяет десериализировать неизменяемый класс или структуру.
Для класса, если единственным конструктором является параметризованный, этот конструктор будет использоваться.
Для структуры или класса с несколькими конструкторами укажите один, который следует использовать, применив атрибут [JsonConstructor]. Если атрибут не используется, открытый конструктор без параметров всегда используется при наличии.
В следующем примере используется атрибут
[JsonConstructor]:using System.Text.Json; using System.Text.Json.Serialization; namespace ImmutableTypes { public struct Forecast { public DateTime Date { get; } public int TemperatureC { get; } public string Summary { get; } [JsonConstructor] public Forecast(DateTime date, int temperatureC, string summary) => (Date, TemperatureC, Summary) = (date, temperatureC, summary); } public class Program { public static void Run() { string json = """ { "date":"2020-09-06T11:31:01.923395-07:00", "temperatureC":-1, "summary":"Cold" } """; Console.WriteLine($"Input JSON: {json}"); var options = JsonSerializerOptions.Web; Forecast forecast = JsonSerializer.Deserialize<Forecast>(json, options); Console.WriteLine($"forecast.Date: {forecast.Date}"); Console.WriteLine($"forecast.TemperatureC: {forecast.TemperatureC}"); Console.WriteLine($"forecast.Summary: {forecast.Summary}"); string roundTrippedJson = JsonSerializer.Serialize<Forecast>(forecast, options); Console.WriteLine($"Output JSON: {roundTrippedJson}"); } } } // Produces output like the following example: // //Input JSON: { "date":"2020-09-06T11:31:01.923395-07:00","temperatureC":-1,"summary":"Cold"} //forecast.Date: 9 / 6 / 2020 11:31:01 AM //forecast.TemperatureC: -1 //forecast.Summary: Cold //Output JSON: { "date":"2020-09-06T11:31:01.923395-07:00","temperatureC":-1,"summary":"Cold"}Imports System.Text.Json Imports System.Text.Json.Serialization Namespace ImmutableTypes Public Structure Forecast Public ReadOnly Property [Date] As Date Public ReadOnly Property TemperatureC As Integer Public ReadOnly Property Summary As String <JsonConstructor> Public Sub New([Date] As Date, TemperatureC As Integer, Summary As String) Me.Date = [Date] Me.TemperatureC = TemperatureC Me.Summary = Summary End Sub End Structure Public NotInheritable Class Program Public Shared Sub Main() Dim json As String = "{""date"":""2020-09-06T11:31:01.923395-07:00"",""temperatureC"":-1,""summary"":""Cold""}" Console.WriteLine($"Input JSON: {json}") Dim forecast1 As Forecast = JsonSerializer.Deserialize(Of Forecast)(json, JsonSerializerOptions.Web) Console.WriteLine($"forecast.Date: {forecast1.[Date]}") Console.WriteLine($"forecast.TemperatureC: {forecast1.TemperatureC}") Console.WriteLine($"forecast.Summary: {forecast1.Summary}") Dim roundTrippedJson As String = JsonSerializer.Serialize(forecast1, JsonSerializerOptions.Web) Console.WriteLine($"Output JSON: {roundTrippedJson}") End Sub End Class End Namespace ' Produces output like the following example: ' 'Input JSON: { "date":"2020-09-06T11:31:01.923395-07:00","temperatureC":-1,"summary":"Cold"} 'forecast.Date: 9 / 6 / 2020 11:31:01 AM 'forecast.TemperatureC: -1 'forecast.Summary: Cold 'Output JSON: { "date":"2020-09-06T11:31:01.923395-07:00","temperatureC":-1,"summary":"Cold"}В .NET 7 и более ранних версиях атрибут
[JsonConstructor]можно использовать только с общедоступными конструкторами.
В .NET 8 и более поздних версиях режим отражения поддерживает недоступные конструкторы, помеченные как [JsonConstructor]. Начиная с .NET 11, режим создания источников также поддерживает их.
Имена параметров параметризованного конструктора должны соответствовать именам и типам свойств. Сопоставление не учитывает регистр, а параметр конструктора должен соответствовать фактическому имени свойства, даже если для переименования свойства используется [JsonPropertyName]. В следующем примере имя свойства TemperatureC изменяется на celsius в формате JSON, но параметр конструктора по-прежнему называется temperatureC:
using System.Text.Json;
using System.Text.Json.Serialization;
namespace ImmutableTypesCtorParms
{
public readonly struct Forecast
{
public DateTime Date { get; }
[JsonPropertyName("celsius")]
public int TemperatureC { get; }
public string Summary { get; }
[JsonConstructor]
public Forecast(DateTime date, int temperatureC, string summary) =>
(Date, TemperatureC, Summary) = (date, temperatureC, summary);
}
public class Program
{
public static void Run()
{
string json = """
{
"date":"2020-09-06T11:31:01.923395-07:00",
"celsius":-1,
"summary":"Cold"
}
""";
Console.WriteLine($"Input JSON: {json}");
var options = JsonSerializerOptions.Web;
Forecast forecast = JsonSerializer.Deserialize<Forecast>(json, options);
Console.WriteLine($"forecast.Date: {forecast.Date}");
Console.WriteLine($"forecast.TemperatureC: {forecast.TemperatureC}");
Console.WriteLine($"forecast.Summary: {forecast.Summary}");
string roundTrippedJson =
JsonSerializer.Serialize<Forecast>(forecast, options);
Console.WriteLine($"Output JSON: {roundTrippedJson}");
}
}
}
// Produces output like the following example:
//
//Input JSON: { "date":"2020-09-06T11:31:01.923395-07:00","celsius":-1,"summary":"Cold"}
//forecast.Date: 9 / 6 / 2020 11:31:01 AM
//forecast.TemperatureC: -1
//forecast.Summary: Cold
//Output JSON: { "date":"2020-09-06T11:31:01.923395-07:00","celsius":-1,"summary":"Cold"}
Помимо [JsonPropertyName], следующие атрибуты поддерживают десериализацию с параметризованными конструкторами:
Параметры конструктора по ссылке
Начиная с .NET 11, JsonSerializer десериализует типы, параметры конструктора которых имеют модификаторы in, out, ref и ref readonly.
| Модификатор параметров | Поведение десериализации |
|---|---|
in, ref и ref readonly |
Сериализатор привязывает каждый параметр по имени и использует его базовый тип элемента для сопоставления типов. |
out |
Сериализатор не привязывает параметр к JSON. Он удаляет значение, которое назначает конструктор. |
В следующем конструкторе сериализатор связывает temperatureC с данными из JSON. Не удаётся выполнить привязку isValid:
public Forecast(in int temperatureC, out bool isValid)
{
TemperatureC = temperatureC;
isValid = true;
}
В языке Visual Basic параметр конструктора ByRef ведет себя в соответствии с поведением ref, показанным в таблице:
Public Sub New(ByRef temperatureC As Integer)
TemperatureC = temperatureC
End Sub
Записи
Записи также поддерживаются для сериализации и десериализации, как показано в следующем примере:
using System.Text.Json;
namespace Records
{
public record Forecast(DateTime Date, int TemperatureC)
{
public string? Summary { get; init; }
};
public class Program
{
public static void Run()
{
Forecast forecast = new(DateTime.Now, 40)
{
Summary = "Hot!"
};
string forecastJson = JsonSerializer.Serialize<Forecast>(forecast);
Console.WriteLine(forecastJson);
Forecast? forecastObj = JsonSerializer.Deserialize<Forecast>(forecastJson);
Console.WriteLine(forecastObj);
}
}
}
// Produces output like the following example:
//
//{ "Date":"2020-10-21T15:26:10.5044594-07:00","TemperatureC":40,"Summary":"Hot!"}
//Forecast { Date = 10 / 21 / 2020 3:26:10 PM, TemperatureC = 40, Summary = Hot! }
Вы можете применить любой из атрибутов к именам свойств, используя целевой объект property: для атрибута. Дополнительные сведения о позиционных записях см. в статье о записях в справочнике по языку C#.
Недоступные члены и методы доступа к свойствам
Вы можете включить использование недоступного метода доступа для свойства с помощью атрибута [JsonInclude], как показано в следующем примере:
using System.Text.Json;
using System.Text.Json.Serialization;
namespace NonPublicAccessors
{
public class Forecast
{
public DateTime Date { get; init; }
[JsonInclude]
public int TemperatureC { get; private set; }
[JsonInclude]
public string? Summary { private get; set; }
};
public class Program
{
public static void Run()
{
string json = """
{
"Date":"2020-10-23T09:51:03.8702889-07:00",
"TemperatureC":40,
"Summary":"Hot"
}
""";
Console.WriteLine($"Input JSON: {json}");
Forecast forecastDeserialized = JsonSerializer.Deserialize<Forecast>(json)!;
Console.WriteLine($"Date: {forecastDeserialized.Date}");
Console.WriteLine($"TemperatureC: {forecastDeserialized.TemperatureC}");
json = JsonSerializer.Serialize<Forecast>(forecastDeserialized);
Console.WriteLine($"Output JSON: {json}");
}
}
}
// Produces output like the following example:
//
//Input JSON: { "Date":"2020-10-23T09:51:03.8702889-07:00","TemperatureC":40,"Summary":"Hot"}
//Date: 10 / 23 / 2020 9:51:03 AM
//TemperatureC: 40
//Output JSON: { "Date":"2020-10-23T09:51:03.8702889-07:00","TemperatureC":40,"Summary":"Hot"}
Imports System.Text.Json
Imports System.Text.Json.Serialization
Namespace NonPublicAccessors
Public Class Forecast
Public Property [Date] As Date
Private _temperatureC As Integer
<JsonInclude>
Public Property TemperatureC As Integer
Get
Return _temperatureC
End Get
Private Set(Value As Integer)
_temperatureC = Value
End Set
End Property
Private _summary As String
<JsonInclude>
Public Property Summary As String
Private Get
Return _summary
End Get
Set(Value As String)
_summary = Value
End Set
End Property
End Class
Public NotInheritable Class Program
Public Shared Sub Main()
Dim json As String = "{""Date"":""2020-10-23T09:51:03.8702889-07:00"",""TemperatureC"":40,""Summary"":""Hot""}"
Console.WriteLine($"Input JSON: {json}")
Dim forecastDeserialized As Forecast = JsonSerializer.Deserialize(Of Forecast)(json)
Console.WriteLine($"Date: {forecastDeserialized.[Date]}")
Console.WriteLine($"TemperatureC: {forecastDeserialized.TemperatureC}")
json = JsonSerializer.Serialize(forecastDeserialized)
Console.WriteLine($"Output JSON: {json}")
End Sub
End Class
End Namespace
' Produces output like the following example:
'
'Input JSON: { "Date":"2020-10-23T09:51:03.8702889-07:00","TemperatureC":40,"Summary":"Hot"}
'Date: 10 / 23 / 2020 9:51:03 AM
'TemperatureC: 40
'Output JSON: { "Date":"2020-10-23T09:51:03.8702889-07:00","TemperatureC":40,"Summary":"Hot"}
При наличии свойства с приватным методом setter, его все равно можно десериализовать.
В .NET 8 и более поздних версиях можно также использовать атрибут [JsonInclude], чтобы выбрать элементы, не являющиеся открытыми, в контракт сериализации для данного типа.
Начиная с .NET 11, генерация исходного кода поддерживает члены private, internal и protected, которые вы помечаете с помощью [JsonInclude]. Он также поддерживает методы доступа private, internal и protected для свойств, которые вы помечаете с помощью [JsonInclude]. Генерация исходного кода также поддерживает недоступные конструкторы, помеченные [JsonConstructor].
Заметка
В .NET 10 и более ранних версиях генерация исходного кода не поддерживает члены или методы доступа private или protected. Применение атрибута [JsonInclude] к члену или свойству не удаляет это ограничение. Генерация исходного кода поддерживает только члены и аксессоры internal, если они находятся в той же сборке, что и созданный JsonSerializerContext. Он не поддерживает недоступные конструкторы, даже если пометить их с помощью [JsonConstructor].
Свойства только для инициализации
System.Text.Json десериализует свойства, доступные только для init, как и любые другие свойства, для которых можно задать значение. Начиная с .NET 11, сгенерированный исходным кодом сеттер вызывается только тогда, когда JSON-данные содержат это свойство. Опущенное свойство сохраняет значение инициализатора.
Свойства только для чтения
В .NET 8 и более поздних версиях можно десериализировать свойства только для чтения или те, которые не имеют метода задания либо частного, либо общедоступного. Хотя вы не можете изменить экземпляр, на который ссылается свойство, если тип свойства меняется, его можно изменить. Например, можно добавить элемент в список. Чтобы десериализировать свойство только для чтения, необходимо задать поведение обработки создания объекта, чтобы заполнить вместо заменить. Например, можно аннотировать свойство с помощью атрибута JsonObjectCreationHandlingAttribute.
class A
{
[JsonObjectCreationHandling(JsonObjectCreationHandling.Populate)]
public List<int> Numbers1 { get; } = new List<int>() { 1, 2, 3 };
}
Дополнительные сведения см. в разделе Заполнение инициализированных свойств.