Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Niezmienny typ jest taki, który uniemożliwia zmianę wszelkich wartości właściwości lub pól obiektu po jego utworzeniu. Typ może być rekordem, nie mieć właściwości publicznych lub pól, mieć właściwości tylko do odczytu lub mieć właściwości z ustawieniami prywatnymi lub tylko do inicjalizacji. System.String jest przykładem niezmiennego typu. System.Text.Json Udostępnia różne sposoby deserializacji danych JSON na niezmienne typy.
Konstruktory sparametryzowane
Domyślnie System.Text.Json używa domyślnego publicznego konstruktora bez parametrów. Można jednak powiedzieć, że używa konstruktora sparametryzowanego, co umożliwia deserializowanie niezmiennej klasy lub struktury.
W przypadku klasy, jeśli jedynym konstruktorem jest sparametryzowany konstruktor, zostanie on użyty.
W przypadku struktury lub klasy z wieloma konstruktorami określ ten, który ma być używany, stosując atrybut [JsonConstructor]. Jeśli atrybut nie jest używany, publiczny konstruktor bez parametrów jest zawsze używany, jeśli istnieje.
W poniższym przykładzie użyto atrybutu
[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"}W programie .NET 7 i starszych wersjach
[JsonConstructor]atrybut może być używany tylko z konstruktorami publicznymi.
W .NET 8 lub nowszych wersjach tryb odbicia obsługuje konstruktory inne niż publiczne oznaczone jako [JsonConstructor]. Począwszy od .NET 11, tryb generowania źródła również je obsługuje.
Nazwy parametrów konstruktora sparametryzowanego muszą być zgodne z nazwami i typami właściwości. pl-PL: Dopasowanie jest bez uwzględniania wielkości liter, a parametr konstruktora musi być zgodny z rzeczywistą nazwą właściwości, nawet jeśli używasz [JsonPropertyName], aby zmienić nazwę właściwości. W poniższym przykładzie nazwa TemperatureC właściwości została zmieniona na celsius w formacie JSON, ale parametr konstruktora nadal nosi nazwę 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"}
Oprócz [JsonPropertyName], następujące atrybuty obsługują deserializację z konstruktorami z parametrami:
Parametry konstruktora przekazywane przez referencję
Począwszy od platformy .NET 11 JsonSerializer deserializuje typy, których parametry konstruktora używają modyfikatorów in, ref, out i ref readonly.
| Modyfikator parametrów | Zachowanie deserializacji |
|---|---|
in, refi ref readonly |
Serializator wiąże każdy parametr według nazwy i używa jego podstawowego typu elementu do dopasowywania typów. |
out |
Serializator nie wiąże parametru z formatem JSON. Odrzuca wartość przypisaną przez konstruktora. |
W poniższym konstruktorze serializator wiąże temperatureC na podstawie danych JSON. Nie wiąże się z isValid:
public Forecast(in int temperatureC, out bool isValid)
{
TemperatureC = temperatureC;
isValid = true;
}
W języku Visual Basic parametr konstruktora ByRef działa zgodnie z zachowaniem ref przedstawionym w tabeli:
Public Sub New(ByRef temperatureC As Integer)
TemperatureC = temperatureC
End Sub
Rekordy
Rekordy są również obsługiwane zarówno w przypadku serializacji, jak i deserializacji, jak pokazano w poniższym przykładzie:
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! }
Do nazw właściwości można zastosować dowolne atrybuty, używając celu property: na atrybucie. Aby uzyskać więcej informacji na temat rekordów pozycyjnych, zobacz artykuł dotyczący rekordów w dokumentacji języka C#.
Niepubliczni członkowie i akcesory właściwości
Możesz włączyć użycie niepublicznego akcesora dla właściwości, korzystając z atrybutu [JsonInclude], jak pokazano w poniższym przykładzie.
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"}
Dołączając właściwość z prywatnym ustawieniem, nadal możesz zdeserializować tę właściwość.
W programie .NET 8 i nowszych wersjach można również użyć atrybutu [JsonInclude], aby wybrać elementy członkowskie inne niż publiczne do kontraktu serializacji dla danego typu.
Począwszy od platformy .NET 11 generator kodu źródłowego obsługuje składowe private, internal i protected, które oznaczysz za pomocą [JsonInclude]. Obsługuje również akcesory private, internal i protected dla właściwości, które oznaczysz za pomocą [JsonInclude]. Generowanie kodu źródłowego obsługuje również niedostępne konstruktory oznaczone atrybutem [JsonConstructor].
Uwaga / Notatka
W platformie .NET 10 i starszych wersjach generowanie kodu źródłowego nie obsługuje składowych private ani protected lub akcesorów. Zastosowanie atrybutu [JsonInclude] do elementu członkowskiego lub właściwości nie powoduje usunięcia tego ograniczenia. Generowanie kodu źródłowego obsługuje składowe i akcesory internal tylko wtedy, gdy znajdują się w tej samej asembacji co wygenerowany element JsonSerializerContext. Nie obsługuje niedostępnych konstruktorów, nawet jeśli oznaczysz je znacznikiem [JsonConstructor].
Właściwości dostępne tylko przy inicjalizacji
System.Text.Json deserializuje właściwości init-only tak samo jak każdą inną właściwość, którą można ustawić. Począwszy od .NET 11, moduł ustawiania generowanego przez źródło jest uruchamiany tylko wtedy, gdy ładunek JSON zawiera właściwość . Pominięta właściwość zachowuje wartość nadaną przez inicjalizator.
Właściwości tylko do odczytu
W .NET 8 i nowszych wersjach właściwości tylko do odczytu lub te, które nie mają metody ustawiającej, ani prywatnej, ani publicznej, mogą być również deserializowane. Chociaż nie można zmienić wystąpienia, do którego odwołuje się właściwość, jeśli typ właściwości jest modyfikowalny, można go zmodyfikować. Można na przykład dodać element do listy. Aby zdeserializować właściwość tylko do odczytu, należy ustawić zachowanie obsługi tworzenia obiektu na wypełnić zamiast zastąpić. Można na przykład dodać adnotację do właściwości za pomocą atrybutu JsonObjectCreationHandlingAttribute .
class A
{
[JsonObjectCreationHandling(JsonObjectCreationHandling.Populate)]
public List<int> Numbers1 { get; } = new List<int>() { 1, 2, 3 };
}
Aby uzyskać więcej informacji, zobacz Wypełnianie zainicjowanych właściwości.