Använda oföränderliga typer och egenskaper
En oföränderlig typ som hindrar dig från att ändra egenskaps- eller fältvärden för ett objekt när det har instansierats. Typen kan vara en post, har inga offentliga egenskaper eller fält, har skrivskyddade egenskaper eller har egenskaper med privata eller init-endast setters. System.String är ett exempel på en oföränderlig typ. System.Text.Json innehåller olika sätt som du kan deserialisera JSON till oföränderliga typer.
Parameteriserade konstruktorer
Som standard använder System.Text.Json
standardkonstruktorn utan offentliga parametrar. Du kan dock be den att använda en parametriserad konstruktor, vilket gör det möjligt att deserialisera en oföränderlig klass eller struct.
Om den enda konstruktorn i en klass är en parameteriserad sådan, kommer den konstruktorn att användas.
För en struct eller en klass med flera konstruktorer anger du den som ska användas genom att använda attributet [JsonConstructor]. När attributet inte används används alltid en offentlig parameterlös konstruktor om den finns.
I följande exempel används attributet
[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 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"}
I .NET 7 och tidigare versioner kan attributet
[JsonConstructor]
endast användas med offentliga konstruktorer.
Parameternamnen för en parametriserad konstruktor måste matcha egenskapsnamnen och typerna. Matchningen är skiftlägeskänslig och konstruktorparametern måste matcha det faktiska egenskapsnamnet även om du använder [JsonPropertyName] för att byta namn på en egenskap. I följande exempel ändras namnet på egenskapen TemperatureC
till celsius
i JSON, men konstruktorparametern heter fortfarande 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"}
Förutom [JsonPropertyName]
stöder följande attribut deserialisering med parametriserade konstruktorer:
Arkiv
Register stöds också för både serialisering och deserialisering, enligt följande exempel:
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! }
Du kan använda vilket som helst av attributen på egenskapsnamnen genom att använda property:
som mål på attributet. För mer information om poster av positionell typ, se artikeln om -poster i språkreferensen för C#.
Icke-offentliga medlemmar och egenskapsåtkomster
Du kan aktivera användning av en icke-offentlig "" accessor "" på en egenskap med hjälp av attributet "" [JsonInclude] "", som visas i följande exempel:
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"}
Genom att inkludera en egenskap med en privat setter kan du ändå deserialisera egenskapen.
I .NET 8 och senare versioner kan du också använda attributet [JsonInclude] för att välja icke-offentliga medlemmar till serialiseringskontraktet för en viss typ.
Not
I källgenereringsläge kan du inte serialisera private
medlemmar eller använda private
accessorer genom att sätta attributet [JsonInclude] på dem. Du kan bara serialisera internal
-medlemmar eller använda internal
-accessorer om de är i samma assembly som den genererade JsonSerializerContext.
Skrivskyddade egenskaper
I .NET 8 och senare versioner kan skrivskyddade egenskaper, eller de som inte har någon setter, antingen privata eller offentliga, också deserialiseras. Du kan inte ändra den instans som egenskapen refererar till, men om egenskapens typ är föränderlig kan du ändra den. Du kan till exempel lägga till ett element i en lista. Om du vill deserialisera en skrivskyddad egenskap måste du ange dess beteende för skapande av objekt till fylla i i stället för ersätta. Du kan till exempel kommentera egenskapen med attributet JsonObjectCreationHandlingAttribute.
class A
{
[JsonObjectCreationHandling(JsonObjectCreationHandling.Populate)]
public List<int> Numbers1 { get; } = new List<int>() { 1, 2, 3 };
}
För mer information, se Fyll i initierade egenskaper.