Nota
O acceso a esta páxina require autorización. Pode tentar iniciar sesión ou modificar os directorios.
O acceso a esta páxina require autorización. Pode tentar modificar os directorios.
A partir de .NET 9, JsonSerializer cuenta con una funcionalidad (limitada) para aplicar tipos de referencia que no aceptan valores NULL en la serialización y deserialización. Puede activar o desactivar esta funcionalidad con la flag JsonSerializerOptions.RespectNullableAnnotations.
Por ejemplo, el siguiente fragmento de código genera una excepción JsonException durante la serialización con un mensaje como el siguiente:
La propiedad o el campo "Name" en el tipo "Person" no permite obtener valores NULL. Aquí podría pensar en actualizar la nulabilidad de las anotaciones.
public static void RunIt()
{
#nullable enable
JsonSerializerOptions options = new()
{
RespectNullableAnnotations = true
};
Person invalidValue = new(Name: null!);
JsonSerializer.Serialize(invalidValue, options);
}
record Person(string Name);
Del mismo modo, RespectNullableAnnotations aplica la nulabilidad en la deserialización. El siguiente fragmento de código genera una excepción JsonException durante la serialización con un mensaje como el siguiente:
El parámetro del constructor 'Name' en el tipo 'Person' no permite valores NULL. Aquí podría pensar en actualizar la nulabilidad de las anotaciones.
public static void RunIt()
{
#nullable enable
JsonSerializerOptions options = new()
{
RespectNullableAnnotations = true
};
string json = """{"Name":null}""";
JsonSerializer.Deserialize<Person>(json, options);
}
record Person(string Name);
Sugerencia
- Puede configurar la nulabilidad en un ámbito de propiedad determinado mediante las propiedades IsGetNullable y IsSetNullable.
- El compilador de C# usa los atributos
[NotNull],[AllowNull],[MaybeNull]y[DisallowNull]para ajustar las anotaciones en captadores y establecedores. Esta característica System.Text.Json también reconoce estos atributos. (Para obtener más información sobre los atributos, consulte Atributos del análisis estático de estado nulo).
Limitaciones
Debido a la forma en que se implementan los tipos de referencia que no aceptan valores NULL, esta característica viene acompañada de algunas limitaciones importantes. Estudie bien estas limitaciones antes de activar la característica. La raíz del problema es que la nulabilidad del tipo de referencia no tiene ninguna representación de primera clase en el lenguaje intermedio (IL). Por lo tanto, las expresiones MyPoco y MyPoco? son indistinguibles desde la perspectiva de la reflexión en tiempo de ejecución. Aunque el compilador intenta compensarlo mediante la emisión de metadatos de atributo (consulte ejemplo sharplab.io), estos metadatos están restringidos a anotaciones de miembros no genéricos que tienen como ámbito una definición de tipo determinada. Esta limitación es la razón por la que la flag solo valida las anotaciones de nulabilidad presentes en propiedades, campos y parámetros de constructor no genéricos.
System.Text.Json no admite la aplicación de nulabilidad en:
- Tipos de nivel superior o el tipo que se pasa al realizar la primera llamada a
JsonSerializer.Deserialize()oJsonSerializer.Serialize(). - Tipos de elementos de colección: por ejemplo, los tipos
List<string>yList<string?>son indistinguibles. - Todas las propiedades, campos o parámetros de constructor que son genéricos.
Si quiere que se aplique la nulabilidad en estos casos, elabore su tipo para que sea una estructura (ya que no admiten valores NULL) o cree un convertidor personalizado que invalide la propiedad HandleNull en true.
Conmutador de característica
Puede activar el parámetro de configuración RespectNullableAnnotations de forma global mediante la opción de la característica System.Text.Json.Serialization.RespectNullableAnnotationsDefault. Agregue el siguiente elemento de MSBuild al archivo del proyecto (por ejemplo, archivo .csproj):
<ItemGroup>
<RuntimeHostConfigurationOption Include="System.Text.Json.Serialization.RespectNullableAnnotationsDefault" Value="true" />
</ItemGroup>
La API RespectNullableAnnotationsDefault se ha implementado como una flag voluntaria en .NET 9 para evitar interrumpir las aplicaciones existentes. Si va a escribir una nueva aplicación, le recomendamos que habilite esta flag en el código.
Relación entre parámetros que aceptan valores NULL y opcionales
RespectNullableAnnotations no amplía esta aplicación a valores JSON no especificados, ya que System.Text.Json trata las propiedades correspondientes y que no aceptan valores NULL como conceptos ortogonales. Por ejemplo, el siguiente fragmento de código no genera una excepción durante la deserialización:
public static void RunIt()
{
JsonSerializerOptions options = new()
{
RespectNullableAnnotations = true
};
var result = JsonSerializer.Deserialize<MyPoco>("{}", options);
Console.WriteLine(result.Name is null); // True.
}
class MyPoco
{
public string Name { get; set; }
}
Esta acción se deriva del propio lenguaje C#, donde puede tener propiedades necesarias que aceptan valores NULL:
MyPoco poco = new() { Value = null }; // No compiler warnings.
class MyPoco
{
public required string? Value { get; set; }
}
Además, también puede tener propiedades opcionales que no aceptan valores NULL:
class MyPoco
{
public string Value { get; set; } = "default";
}
La misma ortogonalidad se aplica a los parámetros del constructor:
record MyPoco(
string RequiredNonNullable,
string? RequiredNullable,
string OptionalNonNullable = "default",
string? OptionalNullable = "default"
);
Valores que faltan frente a valores NULL
Es importante comprender la distinción entre las propiedades JSON que faltan y las propiedades con valores explícitos null al establecer RespectNullableAnnotations. JavaScript distingue entre undefined (propiedad que falta) y null (valor NULL explícito). Sin embargo, .NET no tiene un undefined concepto, por lo que en .NET, ambos casos se deserializan a null.
Durante la deserialización, cuando RespectNullableAnnotations es true:
Un valor NULL explícito produce una excepción para las propiedades que no aceptan valores NULL. Por ejemplo,
{"Name":null}lanza una excepción al deserializar a una propiedadstring Nameque no acepta valores nulos.Una propiedad que falta no produce una excepción, incluso para propiedades que no aceptan valores NULL. Por ejemplo,
{}no lanza una excepción al deserializar una propiedadstring Nameque no admite valores nulos. El serializador no establece la propiedad y lo deja en su valor predeterminado del constructor. En el caso de un tipo de referencia no anulable sin inicializar, esto da como resultadonull, que desencadena una advertencia del compilador.En el código siguiente se muestra cómo una propiedad que falta no produce una excepción durante la deserialización:
public static void RunIt() { #nullable enable JsonSerializerOptions options = new() { RespectNullableAnnotations = true }; // Missing property - does NOT throw an exception. string jsonMissing = """{}"""; var resultMissing = JsonSerializer.Deserialize<Person>(jsonMissing, options); Console.WriteLine(resultMissing.Name is null); // True. } record Person(string Name);
Esta diferencia de comportamiento se produce porque las propiedades que faltan se tratan como opcionales (no proporcionadas), mientras que los valores explícitos null se tratan como valores proporcionados que infringen la restricción que no acepta valores NULL. Si necesita aplicar que una propiedad debe estar presente en json, use el required modificador o configure la propiedad según sea necesario mediante JsonRequiredAttribute o el modelo de contratos.