【问题标题】:How to avoid needing a root class for a JSON object when using JsonConvert.DeserializeObject使用 JsonConvert.DeserializeObject 时如何避免 JSON 对象需要根类
【发布时间】:2022-11-14 08:17:20
【问题描述】:

鉴于这个 JSON,

{
    "token": {
        "accessToken": "scrciFyGuLAQn6XgKkaBWOxdZA1",
        "issuedAt": "2022-11-06T22:54:27Z",
        "expiresIn": 1799
    }
}

如果我将模型定义为这样,我可以让DeserializeObject 工作

    public class Root
    {
        public Token Token { get; set; }
    }

    public class Token
    {
        public string AccessToken { get; set; }
        public DateTime IssuedAt { get; set; }
        public int ExpiresIn { get; set; }
    }

并使用此调用:

Root myRoot = JsonConvert.DeserializeObject<Root>(apiResponse);

我正在调用的第三方 API 的所有方法都返回类似的 JSON 响应,因为它有一个包含特定类型的单个对象的标头对象,例如:

{
  "user": {
    "preferences": {},
    "address": {},
    "name": {},
    "email": "string",
    "segmentName": "string"
  }
}

这需要一个看起来像这样的模型:

    public class Address
    {
    }

    public class Name
    {
    }

    public class Preferences
    {
    }

    public class Root
    {
        public User user { get; set; }
    }

    public class User
    {
        public Preferences preferences { get; set; }
        public Address address { get; set; }
        public Name name { get; set; }
        public string email { get; set; }
        public string segmentName { get; set; }
    }

我不想为每个 JSON 响应定义一个不同的 Root 类。有没有办法避免这种情况?

编辑 14/11。

另一个 JSON 响应如下所示:

{
  "provider": {
    "TOTAL": {
      "count": 0
    }
  }
}

同样,它是一个包含我需要的特定对象的“空”根对象。

作为宰茨曼在他的评论中指出,通过键入 DeserializeObject 调用以使用 &lt;Dictionary, T&gt;,其中 T 是我所追求的实际对象(例如 TokenUserProvider),它绕过需要一个根对象。

【问题讨论】:

  • 有很多方法。另一种方法是JsonConvert.DeserializeObject&lt;Dictionary&lt;string, User&gt;&gt;()["user"]
  • 你的第三个 json 是什么样的?你在寻找任何可能的 json 的通用类吗?
  • @zaitsman。这对我有用。谢谢。所以我不再需要创建一个单独的根类。

标签: c# json.net json-deserialization


【解决方案1】:

我认为定义Root 对象是更好的方法,因为它明确定义了预期的json 结构,但如果您愿意,可以通过JObject (docs) 使用Newtonsoft 的LINQ API:

var jObject = JObject.Parse(json);
var user = jObject["user"].ToObject<User>();

可以通过 System.Text.Json 的 JsonNode API 完成类似的操作(从 .NET 6 开始可用)。

【讨论】:

  • JsonConvert.DeserializeObject&lt;User&gt;(jObject.ToString())
【解决方案2】:

解决它的一种方法是让包装器将所有可能的“内容”名称定义为属性。然后让一个属性返回反序列化后填充的值。

public class Response<T>
{
   public User User { get; set; }
   public Token Token { get; set; }
   public Token AuthToken { get; set; }
   public XYZ XYZ { get; set; }

   public T Content => GetType().GetProperties().Where(p => p.Name != nameof(Content)).Select(p => p.GetValue(this)).Single(v => v != null) as T;
}

然后,只要有一个像这样反序列化的方法

public T DeserializeResponse<T>(string json)
{
  return Deserialize<Response<T>>(json).Content;
}

还有一种更动态的方法,如果您需要检索太多不同的内容,但这将需要覆盖更多的反射并更深入地反序列化过程。

【讨论】:

  • 正如你所说,这个答案可能对我有用,这取决于我需要反序列化多少这些 JSON 响应。我将在本周花更多时间在这方面,如果它适用于我的场景,我会将其标记为答案。谢谢。
  • @SiBrit 从设计和性能的角度来看都不是一个很好的答案。
猜你喜欢
  • 2017-07-09
  • 1970-01-01
  • 2014-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-04
  • 1970-01-01
  • 2014-05-26
相关资源
最近更新 更多