使用C#Json.NET使用动态键反序列化JSON

问题描述

我从外部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"
            },"acNo":"195267","acBalance":"5.25"
            }
         ],"bankName":"BCD Bank","totalAmount":"15.50"
      }
   ]
}

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

解决方法

处理动态键的典型解决方案是使用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; }
}

您会注意到,我在[JsonProperty]类中添加了一些Account属性,以将JSON中的速记属性名称映射到该类中更友好的属性名称。 [JsonConverter]类的Bank属性告诉序列化程序,我们将使用自定义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

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...