Idioma
Nota
L'accés a aquesta pàgina requereix autorització. Podeu provar d'iniciar la sessió o de canviar els directoris.
L'accés a aquesta pàgina requereix autorització. Podeu provar de canviar els directoris.
Un tipo inmutable es uno que impide que cambie los valores de propiedad o campo de un objeto después de crear una instancia. El tipo puede ser un registro, no tener propiedades o campos públicos, tener propiedades de solo lectura o tener propiedades con establecedores privados o de solo inicialización. System.String es un ejemplo de un tipo inmutable. System.Text.Json proporciona diferentes formas de deserializar JSON en tipos inmutables.
Constructores con parámetros
De forma predeterminada, System.Text.Json usa el constructor sin parámetros público predeterminado. Sin embargo, puede indicarle que use un constructor con parámetros, lo que permite deserializar una clase o estructura inmutables.
Para una clase, si el único constructor es un parametrizado, ese constructor se usará.
Para una estructura o una clase con varios constructores, especifique la que se va a usar aplicando el atributo [JsonConstructor]. Cuando no se usa el atributo , siempre se usa un constructor público sin parámetros si está presente.
En el ejemplo siguiente se usa el 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"}En .NET 7 y versiones anteriores, el atributo
[JsonConstructor]solo se puede usar con constructores públicos.
En .NET 8 y versiones posteriores, el modo de reflexión admite constructores no públicos marcados con [JsonConstructor]. A partir de .NET 11, el modo de generación de código fuente también los admite.
Los nombres de parámetro de un constructor con parámetros deben coincidir con los nombres y tipos de propiedad. La coincidencia no es sensible a mayúsculas y minúsculas, y el parámetro del constructor debe coincidir con el nombre real de la propiedad, incluso si usa [JsonPropertyName] para renombrar una propiedad. En el ejemplo siguiente, el nombre de la propiedad TemperatureC se cambia a celsius en el CÓDIGO JSON, pero el parámetro del constructor todavía se denomina 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"}
Además de [JsonPropertyName], los atributos siguientes admiten la deserialización con constructores con parámetros:
Parámetros por referencia del constructor
A partir de .NET 11, JsonSerializer deserializa tipos cuyos parámetros de constructor usan los modificadores in, ref, out y ref readonly.
| Modificador de parámetros | Comportamiento de la deserialización |
|---|---|
in, ref y ref readonly |
El serializador enlaza cada parámetro por nombre y usa su tipo de elemento subyacente para la coincidencia de tipos. |
out |
El serializador no enlaza el parámetro a JSON. Descarta el valor que asigna el constructor. |
En el constructor siguiente, el serializador enlaza temperatureC desde JSON. No vincula isValid:
public Forecast(in int temperatureC, out bool isValid)
{
TemperatureC = temperatureC;
isValid = true;
}
En Visual Basic, un ByRef parámetro de constructor sigue el ref comportamiento que se muestra en la tabla:
Public Sub New(ByRef temperatureC As Integer)
TemperatureC = temperatureC
End Sub
Archivo
También se admiten registros para la serialización y deserialización, como se muestra en el ejemplo siguiente:
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! }
Puede aplicar cualquiera de los atributos a los nombres de propiedad mediante el property: destino en el atributo. Para obtener más información sobre registros posicionales, consulte el artículo sobre los registros en la referencia de lenguaje C#.
Descriptores de acceso de propiedad y miembros no públicos
Puede habilitar el uso de un descriptor de acceso no público en una propiedad mediante el atributo [JsonInclude], como se muestra en el ejemplo siguiente:
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"}
Al incluir una propiedad con un establecedor privado, todavía puede deserializar esa propiedad.
En .NET 8 y versiones posteriores, también puede usar el atributo [JsonInclude] para incluir miembros no públicos en el contrato de serialización para un tipo determinado.
A partir de .NET 11, la generación de código fuente admite miembros private, internal y protected marcados con [JsonInclude]. También admite private, internal y protected accesores para propiedades que se marquen con [JsonInclude]. La generación de origen también admite constructores inaccesibles marcados con [JsonConstructor].
Nota
En .NET 10 y versiones anteriores, la generación de código fuente no admite miembros ni descriptores de acceso private o protected. La aplicación del atributo [JsonInclude] al miembro o la propiedad no quita esta limitación. La generación de código fuente admite miembros y descriptores de acceso internal solo cuando se encuentran en el mismo ensamblado que el JsonSerializerContext generado. No admite constructores inaccesibles, incluso cuando se marcan con [JsonConstructor].
Propiedades solo de inicialización
System.Text.Json deserializa las propiedades de solo init como cualquier otra propiedad configurable. A partir de .NET 11, un setter generado a partir del código fuente solo se ejecuta cuando la carga útil JSON contiene la propiedad. Una propiedad omitida conserva su valor de inicializador.
Propiedades de solo lectura
En .NET 8 y versiones posteriores, también se pueden deserializar las propiedades de solo lectura o las que no tienen establecedor privado o público. Aunque no se puede cambiar la instancia a la que hace referencia la propiedad, si el tipo de la propiedad es mutable, puede modificarla. Por ejemplo, puede agregar un elemento a una lista. Para deserializar una propiedad de solo lectura, debe establecer su comportamiento de control de creación de objetos en rellenar en lugar de reemplazar. Por ejemplo, puede anotar la propiedad con el atributo JsonObjectCreationHandlingAttribute.
class A
{
[JsonObjectCreationHandling(JsonObjectCreationHandling.Populate)]
public List<int> Numbers1 { get; } = new List<int>() { 1, 2, 3 };
}
Para obtener más información, vea Rellenar las propiedades inicializadas.