共用方式為


尊重可為 Null 的批注

從 .NET 9 開始, JsonSerializer 在串行化和還原串行化中都支援不可為 Null 的參考類型強制執行。 您可以使用 旗標來切換此支援 JsonSerializerOptions.RespectNullableAnnotations

例如,下列代碼段會在 JsonException 串行化期間擲回 ,訊息如下:

類型 'Person' 上的屬性或字段 'Name' 不允許取得 Null 值。 請考慮更新其可為 Null 的註釋。

    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 在還原串行化上強制執行可為 Null。 下列代碼段會在 JsonException 串行化期間擲回 ,訊息如下:

類型 'Person' 上的建構函式參數 'Name' 不允許 Null 值。 請考慮更新其可為 Null 的註釋。

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

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

    record Person(string Name);

提示

限制

由於實作不可為 Null 的參考型別的方式,這項功能具有一些重要的限制。 在開啟功能之前,請先熟悉這些限制。 問題的根目錄是參考類型 Null 屬性在中繼語言中沒有一流的表示法(IL)。 因此,表達式 MyPocoMyPoco? 與 在運行時間反映的角度是無法區分的。 雖然編譯程式會嘗試藉由發出屬性元數據來彌補這一點(請參閱 sharplab.io 範例),但此元數據僅限於限定為特定類型定義的非泛型成員批注。 這項限制是因為旗標只會驗證非泛型屬性、欄位和建構函式參數上存在的可為 Null 性批註。 System.Text.Json 不支援下列作業的 Null 可強制執行:

  • 最上層類型,或進行第一次 JsonSerializer.Deserialize()JsonSerializer.Serialize() 呼叫時傳遞的類型。
  • 集合項目類型-例如, List<string>List<string?> 型別不可區分。
  • 任何泛型的屬性、欄位或建構函式參數。

如果您想要在這些情況下新增可為 Null 強制,請將您的類型模型化為結構(因為它們不承認 Null 值),或撰寫將其 HandleNull 屬性覆寫為 true的自定義轉換器。

功能切換

您可以使用功能參數全域System.Text.Json.Serialization.RespectNullableAnnotationsDefault開啟RespectNullableAnnotations設定。 將下列 MSBuild 專案新增至項目檔(例如 .csproj 檔案):

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

RespectNullableAnnotationsDefault API 已在 .NET 9 中實作為加入宣告旗標,以避免中斷現有的應用程式。 如果您要撰寫新的應用程式,強烈建議您在程式代碼中啟用此旗標。

可為 Null 和選擇性參數之間的關聯性

RespectNullableAnnotations 不會將強制執行延伸至未指定的 JSON 值,因為 System.Text.Json 會將必要和不可為 Null 的屬性視為正交概念。 例如,下列代碼段不會在還原串行化期間擲回例外狀況:

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

此行為源於 C# 語言本身,您可以在其中擁有可為 Null 的必要屬性:

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

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

您也可以擁有不可為 Null 的選擇性屬性:

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

相同的正交性適用於建構函式參數:

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

另請參閱