必需的属性

可以标记某些属性,用于指示其必须存在于 JSON 有效负载中,反序列化才能成功。 同样,可以设置一个选项,来指定 JSON 有效负载中存在所有非可选构造函数参数。 如果其中一个或多个所需的属性不存在,JsonSerializer.Deserialize 方法将引发一个 JsonException

有三种方法可以标记 JSON 反序列化所需的属性或字段:

若要指定 JSON 反序列化所需的所有非可选构造函数参数,请将 JsonSerializerOptions.RespectRequiredConstructorParameters 选项(或者,对于源代码生成,将 RespectRequiredConstructorParameters 属性)设置为 true。 有关详细信息,请参阅非可选构造函数参数部分。

从序列化程序的角度来看,C# required 修饰符和 [JsonRequired] 属性是等效的,两者都映射到同一元数据,即 JsonPropertyInfo.IsRequired。 大多数情况下,只需使用内置的 C# 关键字即可。 但是,在以下情况中,应改用 JsonRequiredAttribute

  • 如果你使用的是 C# 以外的编程语言或 C# 的低级版本。
  • 如果只想将要求应用于 JSON 反序列化。
  • 如果在源生成模式下使用 System.Text.Json 序列化。 在这种情况下,如果使用 required 修饰符,代码不会编译,因为源生成是在编译时发生的。

以下代码片段显示使用 required 关键字修改过的属性示例。 JSON 有效负载中必须有此属性,反序列化才能成功。

public static void RunIt()
{
    // The following line throws a JsonException at run time.
    Console.WriteLine(JsonSerializer.Deserialize<Person>("""{"Age": 42}"""));
}

public class Person
{
    public required string Name { get; set; }
    public int Age { get; set; }
}

也可使用 JsonRequiredAttribute

public static void RunIt()
{
    // The following line throws a JsonException at run time.
    Console.WriteLine(JsonSerializer.Deserialize<Person>("""{"Age": 42}"""));
}

public class Person
{
    [JsonRequired]
    public string Name { get; set; }
    public int Age { get; set; }
}

还可以使用 JsonPropertyInfo.IsRequired 属性,通过协定模型来控制是否需要某个属性:

public static void RunIt()
{
    var options = new JsonSerializerOptions
    {
        TypeInfoResolver = new DefaultJsonTypeInfoResolver
        {
            Modifiers =
            {
                static typeInfo =>
                {
                    if (typeInfo.Kind != JsonTypeInfoKind.Object)
                        return;

                    foreach (JsonPropertyInfo propertyInfo in typeInfo.Properties)
                    {
                        // Strip IsRequired constraint from every property.
                        propertyInfo.IsRequired = false;
                    }
                }
            }
        }
    };

    // Deserialization succeeds even though
    // the Name property isn't in the JSON payload.
    JsonSerializer.Deserialize<Person>("""{"Age": 42}""", options);
}

public class Person
{
    public required string Name { get; set; }
    public int Age { get; set; }
}

非可选构造函数参数

在 .NET 9 之前,基于构造函数的反序列化将所有构造函数参数视为可选参数,如以下示例所示:

var result = JsonSerializer.Deserialize<Person>("{}");
Console.WriteLine(result); // Person { Name = , Age = 0 }

record Person(string Name, int Age);

从 .NET 9 开始,可以设置 RespectRequiredConstructorParameters 标志,以根据需要处理非可选构造函数参数。

public static void RunIt()
{
    JsonSerializerOptions options = new()
    {
        RespectRequiredConstructorParameters = true
    };
    string json = """{"Age": 42}""";

    // The following line throws a JsonException at run time.
    JsonSerializer.Deserialize<Person>(json, options);
}

record Person(string Name, int? Age = null);

功能开关

可以使用 System.Text.Json.Serialization.RespectRequiredConstructorParametersDefault 功能开关全局打开 RespectRequiredConstructorParameters 设置。 将以下 MSBuild 项添加到项目文件(例如,.csproj 文件):

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

RespectRequiredConstructorParametersDefault API 在 .NET 9 中作为选择加入标志实现,以避免中断现有应用程序。 如果要编写新应用程序,强烈建议在代码中启用此标志。

另请参阅