【问题标题】:Deserialize JSON with dynamic keys using C# Json.NET使用 C# Json.NET 使用动态键反序列化 JSON
【发布时间】:2020-09-02 14:02:28
【问题描述】:

我从外部 API 收到以下关于客户银行详细信息的 JSON 响应。

{
   "bankDetails":[
      {
         "ABC Bank":[
            {
               "sNo":1,
               "acNo":"1235465",
               "acBalance":"100.25"
            },
            {
               "sNo":2,
               "acNo":"1235467",
               "acBalance":"50.25"
            }
         ],
         "bankName":"ABC Bank",
         "totalAmount":"150.50"
      },
      {
         "XYZ Bank":[
            {
               "sNo":1,
               "acNo":"1248565",
               "acBalance":"75.25"
            }
         ],
         "bankName":"XYZ Bank",
         "totalAmount":"75.25"
      },
      {
         "BCD Bank":[
            {
               "sNo":1,
               "acNo":"145665",
               "acBalance":"10.25"
            },
            {
               "sNo":2,
               "acNo":"195267",
               "acBalance":"5.25"
            }
         ],
         "bankName":"BCD Bank",
         "totalAmount":"15.50"
      }
   ]
}

我需要使用 JSON.Net 将其反序列化为 C# 类。 C# 类的结构应该是什么,因为第一个键是动态的?每个客户返回的第一个带有银行名称的键会有所不同

【问题讨论】:

  • 你能澄清一下“不同的银行详细信息”吗?
  • 可以是任何其他银行,而不是 ABC、BCD、XYZ 银行

标签: c# json json.net json-deserialization


【解决方案1】:

处理动态键的典型解决方案是使用Dictionary<string, T> 代替常规类。有关此示例,请参阅 How can I deserialize a child object with dynamic (numeric) key names?。但是,该解决方案不适用于您的情况,因为同一对象中还有其他属性没有动态键(bankNametotalAmount),并且这些属性的值是原始值,而值动态属性是一组银行账户。这里更好的解决方案是使用JsonConverter

在我们开始之前,我们需要设置一个类结构来反序列化。这很简单:

class RootObject
{
    public List<Bank> BankDetails { get; set; }
}

[JsonConverter(typeof(BankConverter))]
class Bank
{
    public string BankName { get; set; }
    public decimal TotalAmount { get; set; }
    public List<Account> Accounts { get; set; }
}

class Account
{
    [JsonProperty("sNo")]
    public int SequenceNumber { get; set; }
    [JsonProperty("acNo")]
    public string AccountNumber { get; set; }
    [JsonProperty("acBalance")]
    public decimal Balance { get; set; }
}

您会注意到我在Account 类中添加了一些[JsonProperty] 属性,以将JSON 中的速记属性名称映射到该类中更友好的属性名称。而Bank 类上的[JsonConverter] 属性告诉序列化程序我们将使用自定义BankConverter 来处理该类。

这是BankConverter 的代码。它在内部使用 JObject 以使其更易于阅读和使用 JSON。

class BankConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(Bank);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject obj = JObject.Load(reader);
        Bank bank = new Bank();
        // populate the known properties (bankName and totalAmount)
        serializer.Populate(obj.CreateReader(), bank);
        // now handle the dynamic key
        bank.Accounts = obj[bank.BankName].ToObject<List<Account>>(serializer);
        return bank;
    }

    public override bool CanWrite
    {
        get { return false; }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

有了这些类,您可以像这样反序列化 JSON:

var root = JsonConvert.DeserializeObject<RootObject>(json);

这是一个工作演示:https://dotnetfiddle.net/knsRLv

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-11-22
    • 1970-01-01
    • 1970-01-01
    • 2012-11-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多