首页 > 解决方案 > System.Text.Json.JsonSerializer.Deserialize() 的.net 5.0 签名更改

问题描述

我正在尝试从 .NET Core 3.1 到 .NET 5.0 的步骤,并在使用 .NET Core 时收到一堆可空性警告Deserialize<TValue>(String, JsonSerializerOptions)。快速调查显示签名已从

public static TValue Deserialize<TValue> (string json, System.Text.Json.JsonSerializerOptions options = default);文档)在 .NET Core 3.1 到

public static TValue? Deserialize<TValue> (string json, System.Text.Json.JsonSerializerOptions? options = default);文档)在 .NET 5.0 中。

它看起来是一个合理的改变,但我无法让 null 实际返回,因为所有错误的输入/错误使用都会在我的实验中引发异常,并且文档没有描述为什么调用会返回据我所知,null。

如果反序列化失败将抛出而不是返回 null,那么在我们所有的使用中添加 null 返回检查似乎有点不必要。

我错过了什么?

标签: .net-5system.text.json

解决方案


原始 JSON 提案所示,文本null是格式完美的 JSON:

值可以是双引号中的字符串、数字、 true 或 false 或null,或者对象或数组。这些结构可以嵌套。

RFC 8259: The JavaScript Object Notation (JSON) Data Interchange Format进一步阐明了这一点,它指出格式良好的 JSON 文本只需一个原始值,包括null

JSON 文本是一系列标记。标记集包括六个结构字符、字符串、数字和三个文字名称 [false、true 和 null]。

JSON 文本是一个序列化的值。请注意,某些先前的 JSON 规范将 JSON 文本限制为对象或数组。仅生成需要 JSON 文本的对象或数组的实现将是可互操作的,因为所有实现都将接受这些作为符合标准的 JSON 文本。

由于null是根据这个最新的 JSON RFC 格式良好的 JSON 文本,JsonSerializer在将其反序列化为引用类型或可为空值类型时不会抛出,而是只返回一个空值:

object? obj1 = JsonSerializer.Deserialize<object>("null"); // Does not throw; explicitly typed for clarity.
Assert.IsNull(obj1);     // Passes
var array = JsonSerializer.Deserialize<int []>("null");    // Does not throw;
Assert.IsNull(array);    // Passes
var nullable = JsonSerializer.Deserialize<int?>("null");   // Does not throw;
Assert.IsNull(nullable); // Passes

相反,以下会生成编译器警告:

#nullable enable
object obj2 = JsonSerializer.Deserialize<object>("null"); // Compiler warning: Converting null literal or possible value to non-nullable type;

并且以下抛出,因为 anint是不可分配的不可空值null 类型

var i = JsonSerializer.Deserialize<int>("null");  // Throws, since int is a non-nullable value type.

如果要在反序列化 JSON 文本时抛出异常null,可以添加以下扩展方法:

public static class ObjectExtensions
{
    public static T ThrowOnNull<T>(this T? value) where T : class => value ?? throw new ArgumentNullException();
}

并做:

var value = JsonSerializer.Deserialize<TValue>(json).ThrowOnNull();

演示小提琴在这里


推荐阅读