Partager via


Respecter les annotations de nullabilité

À partir de .NET 9, JsonSerializer offre un support limité pour l’application des types de référence non nullables dans la sérialisation et la désérialisation. Vous pouvez activer ou désactiver ce support à l’aide de l’indicateur JsonSerializerOptions.RespectNullableAnnotations.

Par exemple, l’extrait de code suivant déclenche une JsonException pendant la sérialisation avec un message comme :

La propriété ou le champ « Name » du type « Person » n’autorise pas les valeurs nulles. Envisagez de mettre à jour son annotation de nullabilité.

    public static void RunIt()
    {
#nullable enable
        JsonSerializerOptions options = new()
        {
            RespectNullableAnnotations = true
        };

        Person invalidValue = new(Name: null!);
        JsonSerializer.Serialize(invalidValue, options);
    }

    record Person(string Name);

De même, RespectNullableAnnotations applique la nullabilité lors de la désérialisation. L’extrait de code suivant déclenche une JsonException pendant la sérialisation avec un message comme :

Le paramètre de constructeur « Name » du type « Person » n’autorise pas les valeurs nulles. Envisagez de mettre à jour son annotation de nullabilité.

    public static void RunIt()
    {
#nullable enable
        JsonSerializerOptions options = new()
        {
            RespectNullableAnnotations = true
        };

        string json = """{"Name":null}""";
        JsonSerializer.Deserialize<Person>(json, options);
    }

    record Person(string Name);

Conseil

Limites

En raison de la façon dont les types de référence non nullables sont implémentés, cette fonctionnalité présente des limitations importantes. Familiarisez-vous avec ces limitations avant d’activer la fonctionnalité. Le problème fondamental est que la nullabilité des types de référence n’a pas de représentation de premier ordre dans le langage intermédiaire (IL). Ainsi, les expressions MyPoco et MyPoco? sont indiscernables du point de vue de la réflexion à l’exécution. Bien que le compilateur tente de compenser cela en émettant des métadonnées d’attributs (voir l’exemple sur sharplab.io), ces métadonnées sont limitées aux annotations des membres non génériques qui sont liées à une définition de type spécifique. Cette limitation explique pourquoi l’indicateur ne valide que les annotations de nullabilité présentes sur les propriétés, champs et paramètres de constructeur non génériques. System.Text.Json ne prend pas en charge l’application de la nullabilité sur :

  • Les types de premier niveau, ou le type passé lors du premier appel à JsonSerializer.Deserialize() ou JsonSerializer.Serialize().
  • Les types d’éléments de collection, comme les types List<string> et List<string?>, sont indiscernables.
  • Les propriétés, champs ou paramètres de constructeur génériques.

Si vous souhaitez ajouter une application de la nullabilité dans ces cas, modélisez votre type comme une structure (puisqu’elles n’admettent pas les valeurs nulles) ou créez un convertisseur personnalisé qui remplace sa propriété HandleNull par true.

Commutateur de fonctionnalité

Vous pouvez activer l’option RespectNullableAnnotations globalement en utilisant le commutateur de fonctionnalité System.Text.Json.Serialization.RespectNullableAnnotationsDefault. Ajoutez l’élément MSBuild suivant à votre fichier de projet (par exemple, le fichier .csproj) :

<ItemGroup>
  <RuntimeHostConfigurationOption Include="System.Text.Json.Serialization.RespectNullableAnnotationsDefault" Value="true" />
</ItemGroup>

L’API RespectNullableAnnotationsDefault a été implémentée comme un indicateur activable dans .NET 9 pour éviter de rompre les applications existantes. Si vous écrivez une nouvelle application, il est fortement recommandé d’activer cet indicateur dans votre code.

Relation entre les paramètres nullable et optionnels

RespectNullableAnnotations n’étend pas l’application aux valeurs JSON non spécifiées, car System.Text.Json traite les propriétés requises et non nullables comme des concepts orthogonaux. Par exemple, l’extrait de code suivant ne déclenche pas d’exception lors de la désérialisation :

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; }
}

Ce comportement provient du langage C# lui-même, où vous pouvez avoir des propriétés requises qui sont nullables :

MyPoco poco = new() { Value = null }; // No compiler warnings.

class MyPoco
{
    public required string? Value { get; set; }
}

Et vous pouvez également avoir des propriétés optionnelles qui ne sont pas nullables :

class MyPoco
{
    public string Value { get; set; } = "default";
}

La même orthogonalité s’applique aux paramètres de constructeur :

record MyPoco(
    string RequiredNonNullable,
    string? RequiredNullable,
    string OptionalNonNullable = "default",
    string? OptionalNullable = "default"
    );

Voir aussi