使用 System.Text.Json 反序列化匿名类型

Posted

技术标签:

【中文标题】使用 System.Text.Json 反序列化匿名类型【英文标题】:Deserialize anonymous type with System.Text.Json 【发布时间】:2020-04-06 08:33:33 【问题描述】:

我正在为 .NET Core 3.x 更新一些应用程序,作为其中的一部分,我正在尝试从 Json.NET 迁移到新的 System.Text.Json 类。使用 Json.NET,我可以像这样反序列化匿名类型:

var token = JsonConvert.DeserializeAnonymousType(jsonStr, new  token = "" ).token;

新的命名空间中是否有等效的方法?

【问题讨论】:

网呢。匿名类型对象缺少无参数构造函数,因此尝试反序列化为匿名类型会引发异常。演示:dotnetfiddle.net/BLsmwg. 相关增强(开放):JsonSerializer support for immutable classes and structs. #38569,标记为里程碑:未来,5.0 好吧,您可以使用自定义 JsonConverter 来完成此操作,但以通用方式这样做会很棘手并且涉及到。 【参考方案1】:

从 .Net 5.0 开始,System.Text.Json 支持对不可变类型以及匿名类型的反序列化。来自How to use immutable types and non-public accessors with System.Text.Json:

System.Text.Json 可以使用参数化构造函数,这使得反序列化不可变类或结构成为可能。 对于一个类,如果唯一的构造函数是参数化构造函数,则将使用该构造函数。

由于匿名类型只有一个构造函数,它们现在可以成功反序列化。为此,请定义一个辅助方法,如下所示:

public static partial class JsonSerializerExtensions

    public static T DeserializeAnonymousType<T>(string json, T anonymousTypeObject, JsonSerializerOptions options = default)
        => JsonSerializer.Deserialize<T>(json, options);

    public static ValueTask<TValue> DeserializeAnonymousTypeAsync<TValue>(Stream stream, TValue anonymousTypeObject, JsonSerializerOptions options = default, CancellationToken cancellationToken = default)
        => JsonSerializer.DeserializeAsync<TValue>(stream, options, cancellationToken); // Method to deserialize from a stream added for completeness

现在你可以这样做了:

var token = JsonSerializerExtensions.DeserializeAnonymousType(jsonStr, new  token = "" ).token;

演示小提琴here.

【讨论】:

【参考方案2】:

请尝试我作为 System.Text.Json 的扩展编写的这个库,以提供缺少的功能:https://github.com/dahomey-technologies/Dahomey.Json。

您会发现对匿名类型的支持。

通过调用命名空间 Dahomey.Json 中定义的扩展方法 SetupExtensions 的 JsonSerializerOptions 来设置 json 扩展:

JsonSerializerOptions options = new JsonSerializerOptions();
options.SetupExtensions();

然后用 JsonSerializerExtensions 静态类型序列化你的类:

var token = JsonSerializerExtensions.DeserializeAnonymousType(jsonStr, new  token = "" , options).token;

【讨论】:

非常好,但 System.Text.Json 对我们的吸引力在于消除了另一个 3rd 方依赖。如果我们必须添加一个库来使其工作,还不如坚持使用 Newtonsoft 我完全理解你的意思。我写这个库而不是继续使用 Newtonsoft 的原因是因为 System.Text.Json 更快,而且因为 Newtonsoft 在一个特定主题上不太灵活:多态性支持 没有原型怎么办?我有一种情况,我需要处理用户输入的未知结构的 json 提要。我不能做原型,因为我不知道他们的 json 会是什么样子。我计划将其作为一个假定的平面数组处理,其中包含我将枚举其字段的对象。 是的,你可以,但我们不再谈论匿名类型。你可以使用 JsonObject ,它就像一个 DOM 对象。

以上是关于使用 System.Text.Json 反序列化匿名类型的主要内容,如果未能解决你的问题,请参考以下文章

如何在反序列化之前使用 System.Text.Json 验证 JSON

使用 System.Text.Json 使用动态键查询或反序列化 json

使用 system.text.json 序列化和反序列化流

在 System.Text.Json 中使用构造函数进行反序列化

在 System.Text.Json 中使用构造函数进行反序列化

将 false 反序列化为 null (System.Text.Json)