为什么 .NET 的 System.Text.Json.JsonSerializer.Deserialize 方法的返回类型在不返回 null 时可以为 null?

And*_*ebb 12 .net c# json deserialization system.text.json

考虑 .NET 6 的System.Text.Json.JsonSerializer.Deserialize方法及其许多重载。

每个都返回object?或 ,TValue?这表明null可以返回。但是,文档指出,如果出现任何错误,则会引发异常。此外,它还声明返回有效值(如果未引发异常)。没有任何地方说明null可以退货。根据我的使用经验,它null永远不会被退回。

(如果您在项目中打开“可空性”,可空返回类型就会出现问题,因为编译器会开始警告您返回的值可能为空- 根据我的经验(以及根据文档),这不是真的。正是这种事情让我急于再次关闭可空性。我知道我可以抑制警告,但我认为这不是重点。)

是否缺少文档?这些方法真的可以返回 null 吗?如果他们不能,那么为什么我们有可为空的返回类型?

Dai*_*Dai 14

  • TValue? Deserialize<TValue>只是 的包装Object? Deserialize(type: typeof(TValue))
  • #nullable注释添加到 C# 8.0 时,System.Type类型并未通过对这些注释的支持进行扩展。
  • Deserialize<TValue>()因此,在运行时,使用 或 的TValue := MyClass?调用站点TValue := MyClass将表现相同,因为该Deserialize方法不知道是否MyClass具有?注释。
    • Deserialize<TValue>方法只知道是否TValue是引用类型(通过typeof(TValue))。
  • 因此,如果您指示JsonSerializer反序列化字符串"null"(这是有效的 JSON并且TValue引用类型,那么它将返回null.
    • ...即使TValue没有?。请记住,人们JsonSerializer不知道(也不可能)知道这一点!
  • 这就是为什么该方法的静态返回类型具有注释?,因为如果没有注释,那么它将错误地断言它从不返回null

可以说 的JsonSerialize设计者可以添加更多的方法来允许调用者静态断言非空性,但他们没有,但如果你真的想这样做,你可以:

就像这样:

public static TValue DeserializeNonNullObject<TValue>( String json )
    where TValue : class
{
    TValue? orNull = JsonSerializer.Deserialize<TValue>( json );
    return orNull ?? throw new JsonException( "Expected deserialized object to be non-null, but encountered null." );
}
Run Code Online (Sandbox Code Playgroud)

  • 非常感谢。这帮助我理解了很多事情。我不知道——或者忘记——“null”是有效的 JSON。 (2认同)

Iva*_* G. 5

根据 RFC 7159 \xe2\x80\x9cnull\xe2\x80\x9d (和 \xe2\x80\x9ctrue\xe2\x80\x9d 和 \xe2\x80\x9cfalse\xe2\x80\x9d)将是有效的 JSON 文本。但是,空字符串不是有效的 JSON。

\n

  • 谢谢!感谢@Dai!我现在明白了。我对其进行了测试并确认了结果: `var x = JsonSerializer.Deserialize&lt;Test&gt;("null"); // 返回 null`. 我终于明白了。所以也许我真的应该打开“可空性”并注意警告!(到目前为止,我一直认为 null 不会被返回。我错了。) (2认同)