Idioma
Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Um tipo imutável é aquele que impede que se altere qualquer propriedade ou valores de campo de um objeto depois de ser instanciado. O tipo pode ser um registo, não ter propriedades ou campos públicos, ter propriedades somente leitura ou ter propriedades com setters privados ou com setters somente para inicialização. System.String é um exemplo de um tipo imutável. System.Text.Json fornece diferentes maneiras de desserializar JSON para tipos imutáveis.
Construtores parametrizados
Por padrão, System.Text.Json usa o construtor sem parâmetros público padrão. No entanto, você pode dizer a ele para usar um construtor parametrizado, o que torna possível desserializar uma classe ou struct imutável.
Para uma classe, se o único construtor for parametrizado, esse construtor será usado.
Para um struct, ou uma classe com vários construtores, especifique o que usar aplicando o atributo [JsonConstructor]. Quando o atributo não é usado, um construtor sem parâmetros público é sempre usado se presente.
O exemplo a seguir usa o atributo
[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"}No .NET 7 e versões anteriores, o atributo
[JsonConstructor]só pode ser usado com construtores públicos.
No .NET 8 e versões posteriores, o modo de reflexão suporta construtores não públicos marcados com [JsonConstructor]. A partir do .NET 11, o modo de geração de código-fonte também os suporta.
Os nomes de parâmetro de um construtor parametrizado devem corresponder aos nomes e tipos de propriedade. A correspondência não diferencia maiúsculas de minúsculas, e o parâmetro do construtor deve corresponder ao nome real da propriedade, mesmo que se utilize [JsonPropertyName] para renomear uma propriedade. No exemplo a seguir, o nome da propriedade TemperatureC é alterado para celsius no JSON, mas o parâmetro do construtor ainda é nomeado 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"}
Além [JsonPropertyName], os seguintes atributos suportam desserialização com construtores parametrizados:
Parâmetros do construtor por referência
A partir do .NET 11, JsonSerializer desserializa tipos cujos parâmetros de construtor usam os inmodificadores , ref, out, e ref readonly modificadores.
| Modificador de parâmetros | Comportamento de desserialização |
|---|---|
in, refe ref readonly |
O serializador associa cada parâmetro pelo nome e usa o seu tipo de elemento subjacente para correspondência de tipos. |
out |
O serializador não associa o parâmetro a JSON. Descarta o valor que o construtor atribui. |
No construtor seguinte, o serializador liga-se temperatureC a partir de JSON. Não se limita isValid:
public Forecast(in int temperatureC, out bool isValid)
{
TemperatureC = temperatureC;
isValid = true;
}
No Visual Basic, um ByRef parâmetro construtor segue o ref comportamento mostrado na tabela:
Public Sub New(ByRef temperatureC As Integer)
TemperatureC = temperatureC
End Sub
Registos
Os registros também são suportados para serialização e desserialização, conforme mostrado no exemplo a seguir:
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! }
Você pode aplicar qualquer um dos atributos aos nomes de propriedade, usando property: como alvo no atributo. Para obter mais informações sobre registros posicionais, consulte o artigo sobre registros na referência da linguagem C#.
Membros não públicos e acessadores de propriedade
Você pode habilitar o uso de um acessador de não público em uma propriedade usando o atributo [JsonInclude], conforme mostrado no exemplo a seguir:
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"}
Ao incluir uma propriedade com um setter privado, você ainda pode desserializar essa propriedade.
No .NET 8 e versões posteriores, você também pode usar o atributo [JsonInclude] para incluir membros não públicos no contrato de serialização para um tipo específico.
A partir do .NET 11, a geração de código-fonte suporta private, internal, e protected os membros que marca com [JsonInclude]. Também suporta private, internal, e protected acessórios nas propriedades que marca com [JsonInclude]. A geração de código-fonte também suporta construtores inacessíveis marcados com [JsonConstructor].
Observação
No .NET 10 e versões anteriores, a geração de código-fonte não suporta privateprotected membros ou acessórios. Aplicar o atributo [JsonInclude] ao membro ou propriedade não remove esta limitação. A geração de código-fonte suporta internal membros e acessores apenas quando estão na mesma assembly que o gerado JsonSerializerContext. Não suporta construtores inacessíveis, mesmo quando os marcas com [JsonConstructor].
Propriedades somente de init
System.Text.Json desserializa initpropriedades apenas - como qualquer outra propriedade setável. A partir do .NET 11, um setter gerado pela fonte só corre quando a carga útil JSON contém a propriedade. Uma propriedade omitida mantém o seu valor inicializador.
Propriedades somente leitura
No .NET 8 e versões posteriores, as propriedades somente leitura, ou aquelas que não têm setter privado ou público, também podem ser desserializadas. Embora não seja possível alterar a instância à qual a propriedade faz referência, se o tipo da propriedade for mutável, você poderá modificá-la. Por exemplo, você pode adicionar um elemento a uma lista. Para desserializar uma propriedade somente leitura, precisas definir o comportamento de criação do objeto para preencher em vez de substituir. Por exemplo, você pode anotar a propriedade com o atributo JsonObjectCreationHandlingAttribute.
class A
{
[JsonObjectCreationHandling(JsonObjectCreationHandling.Populate)]
public List<int> Numbers1 { get; } = new List<int>() { 1, 2, 3 };
}
Para obter mais informações, consulte Preencher propriedades inicializadas.