Sdílet prostřednictvím


Respektovat poznámky s možnou hodnotou null

Počínaje rozhraním .NET 9 má (omezená) podporu pro vynucení referenčních typů bez JsonSerializer hodnoty null v serializaci i deserializaci. Tuto podporu můžete přepnout pomocí příznaku JsonSerializerOptions.RespectNullableAnnotations .

Například následující fragment kódu vyvolá JsonException během serializace zprávu jako:

Vlastnost nebo pole Jméno typu Person neumožňuje získání hodnot null. Zvažte aktualizaci poznámek s nulovou dostupností.

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

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

    record Person(string Name);

RespectNullableAnnotations Podobně vynucuje u deserializace nulovou hodnotu. Následující fragment kódu vyvolá JsonException během serializace zprávu, například:

Parametr konstruktoru Name u typu Person neumožňuje hodnoty null. Zvažte aktualizaci poznámek s nulovou dostupností.

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

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

    record Person(string Name);

Tip

Omezení

Vzhledem k tomu, jak jsou implementované odkazové typy bez hodnoty null, má tato funkce některá důležitá omezení. Před zapnutím této funkce se seznamte s těmito omezeními. Kořenem problému je, že referenční typ nullability nemá žádnou prvotřídní reprezentaci v přechodném jazyce (IL). Výrazy MyPoco a MyPoco? jsou tak nerozlišitelné od pohledu reflexe za běhu. Zatímco se kompilátor snaží vytvořit pro to generováním metadat atributů (viz sharplab.io příklad), tato metadata jsou omezena na ne generické členské poznámky, které jsou vymezeny na konkrétní definici typu. Toto omezení je důvodem, proč příznak ověřuje pouze poznámky nullability, které jsou přítomné u ne generických vlastností, polí a parametrů konstruktoru. System.Text.Json nepodporuje vynucení vynucování nullability pro:

  • Typy nejvyšší úrovně nebo typ, který se předává při prvním JsonSerializer.Deserialize() volání nebo JsonSerializer.Serialize() volání.
  • Typy elementů kolekce , například List<string> a List<string?> typy jsou nerozlišitelné.
  • Všechny vlastnosti, pole nebo parametry konstruktoru, které jsou obecné.

Pokud chcete v těchto případech přidat vynucení nullability, můžete buď modelovat typ jako strukturu (protože nepřipouštějí hodnoty null), nebo vytvořit vlastní převaděč, který přepíše jeho HandleNull vlastnost na true.

Přepínač funkce

Nastavení můžete zapnout RespectNullableAnnotations globálně pomocí System.Text.Json.Serialization.RespectNullableAnnotationsDefault přepínače funkcí. Do souboru projektu přidejte následující položku MSBuild (například soubor .csproj ):

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

Rozhraní RespectNullableAnnotationsDefault API bylo implementováno jako příznak výslovného souhlasu v .NET 9, aby nedocházelo k přerušení stávajících aplikací. Pokud píšete novou aplikaci, důrazně doporučujeme povolit tento příznak ve svém kódu.

Vztah mezi parametry s možnou hodnotou null a volitelnými parametry

RespectNullableAnnotations nerozšíří vynucení na nezadané hodnoty JSON, protože System.Text.Json považuje požadované a nenulovatelné vlastnosti jako orthogonální koncepty. Například následující fragment kódu při deserializaci nevyvolá výjimku:

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

Toto chování vychází ze samotného jazyka C#, kde můžete mít požadované vlastnosti, které mají hodnotu null:

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

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

Můžete také mít volitelné vlastnosti, které nemají hodnotu null:

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

Stejná orthogonalita platí pro parametry konstruktoru:

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

Viz také