Verwenden unveränderlicher Typen und Eigenschaften
Ein unveränderlicher Typ verhindert, dass Sie Eigenschafts- oder Feldwerte eines Objekts ändern, nachdem es instanziiert wurde. Der Typ kann ein Datensatz sein, keine öffentlichen Eigenschaften oder Felder haben, schreibgeschützte Eigenschaften aufweisen oder Eigenschaften mit privaten oder init-only-Settern haben. System.String ist ein Beispiel für einen unveränderlichen Typ. System.Text.Json bietet verschiedene Möglichkeiten zum Deserialisieren von JSON für unveränderliche Typen.
Parametrisierte Konstruktoren
System.Text.Json
verwendet standardmäßig den standardmäßigen öffentlichen parameterlosen Konstruktor. Sie können ihn jedoch anweisen, einen parametrisierten Konstruktor zu verwenden, der es ermöglicht, eine unveränderliche Klasse oder Struktur zu deserialisieren.
Wenn für eine Klasse der einzige Konstruktor ein parametrisierter ist, wird dieser Konstruktor verwendet.
Geben Sie für eine Struktur oder Klasse mit mehreren Konstruktoren den zu verwendenden Konstruktor an, indem Sie das Attribut [JsonConstructor] anwenden. Wenn das Attribut nicht verwendet wird, wird, sofern vorhanden, stets ein öffentlicher parameterloser Konstruktor verwendet.
Im folgenden Beispiel wird das Attribut
[JsonConstructor]
hinzugefügt: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 Main() { 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"}
In .NET 7 und früheren Versionen kann das
[JsonConstructor]
-Attribut nur mit öffentlichen Konstruktoren verwendet werden.
Die Parameternamen eines parametrisierten Konstruktors müssen mit den Eigenschaftsnamen und -typen übereinstimmen. Beim Abgleich wird die Groß-/Kleinschreibung ignoriert, und der Konstruktorparameter muss mit dem tatsächlichen Eigenschaftsnamen übereinstimmen, auch wenn Sie [JsonPropertyName] zum Umbenennen einer Eigenschaft verwenden. Im folgenden Beispiel wird der Name der TemperatureC
-Eigenschaft im JSON-Code in celsius
geändert, aber der Konstruktorparameter heißt weiterhin 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 Main()
{
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"}
Neben [JsonPropertyName]
unterstützen die folgenden Attribute die Deserialisierung mit parametrisierten Konstruktoren:
Datensätze
Datensätze werden auch für Serialisierung und Deserialisierung unterstützt, wie im folgenden Beispiel gezeigt:
using System.Text.Json;
namespace Records
{
public record Forecast(DateTime Date, int TemperatureC)
{
public string? Summary { get; init; }
};
public class Program
{
public static void Main()
{
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! }
Sie können jedes der Attribute auf die Eigenschaftsnamen anwenden, indem Sie das property:
-Ziel des Attributs verwenden. Weitere Informationen zu Positionsdatensätzen finden Sie im Artikel zu Datensätzen in der C#-Sprachreferenz.
Nicht öffentliche Member und Eigenschaftszugriffsmethoden
Sie können die Verwendung einer nicht-öffentlichen Zugriffsmethode in einer Eigenschaft aktivieren, indem Sie das [JsonInclude]-Attribut verwenden, wie im folgenden Beispiel gezeigt:
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 Main()
{
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"}
Indem Sie eine Eigenschaft mit einem privaten Setter einschließen, können Sie diese Eigenschaft trotzdem deserialisieren.
In .NET 8 und höheren Versionen können Sie auch das [JsonInclude]-Attribut verwenden, um nicht-öffentliche Members für den Serialisierungsvertrag eines bestimmten Typs zu aktivieren.
Hinweis
Im Quellgenerierungsmodus können Sie keine Member serialisieren private
oder Zugriffsmethoden verwenden private
, indem Sie diese mit dem [JsonInclude]-Attribut kommentieren. Sie können außerdem nur internal
Member serialisieren oder internal
Zugriffsmethoden verwenden, wenn sie sich in derselben Assembly wie der generierte JsonSerializerContext befinden.
Schreibgeschützte Eigenschaften
In .NET 8 und höheren Versionen können schreibgeschützte Eigenschaften oder solche, die keinen Setter haben, entweder privat oder öffentlich, ebenfalls deserialisiert werden. Sie können die Instanz, auf welche die Eigenschaft verweist, nicht ändern, wenn der Typ der Eigenschaft änderbar ist, sie aber ändern. Sie können z. B. einer Liste ein Element hinzufügen. Um eine schreibgeschützte Eigenschaft zu deserialisieren, müssen Sie das Verhalten bei der Objekterstellung auf auffüllen statt ersetzen setzen. Beispielsweise können Sie die Eigenschaft mit dem JsonObjectCreationHandlingAttribute-Attribut kommentieren.
class A
{
[JsonObjectCreationHandling(JsonObjectCreationHandling.Populate)]
public List<int> Numbers1 { get; } = new List<int>() { 1, 2, 3 };
}
Weitere Informationen finden Sie unter Auffüllen initialisierter Eigenschaften.