如何将 JSON 反序列化为具有多个 List<T> 参数的 .NET 对象?

Posted

技术标签:

【中文标题】如何将 JSON 反序列化为具有多个 List<T> 参数的 .NET 对象?【英文标题】:How can I deserialize a JSON to a .NET object with several List<T> parameters? 【发布时间】:2022-01-23 20:42:36 【问题描述】:

我正在使用 this library (FireSharp) 访问 Firebase。我检索了一个 json 作为 FirebaseResponse 的主体(基本上是状态和主体),效果很好,看起来像这样(所有测试数据):

"\"Cobros\":\"1001\":\"Estado\":\"Cobrado\",\"Repartidor\":124,\"1112\":\"Estado\":\"Pendiente\",\"Repartidor\":124,\"Pedidos\":\"1111\":\"Estado\":\"Entregado\",\"Repartidor\":123,\"Repartidores\":\"123\":\"ID android\":\"asdadada\",\"Terminal\":123,\"124\":\"ID Android\":\"dggrefawe\",\"Terminal\":124"

Firebase 结构看起来 like this,其后面带有一些参数。 我需要反序列化 Json 以将其嵌入到具有多个列表参数的对象中,一个用于 18500 后面的每个节点。我已经检查了this question,这是我到目前为止的代码:

    public class cargaFirebase
    
        [JsonProperty("Cobros")]
        public List<documentoFirebase> carfb_cobros  get; set; 
        [JsonProperty("Pedidos")]
        public List<documentoFirebase> carfb_pedidos  get; set; 
        [JsonProperty("Repartidores")]
        public List<repartidorFirebase> carfb_repartidores  get; set; 
    

然后反序列化尝试...

FirebaseResponse resp = fbClient.Get(request);
cargaFirebase carga_res = JsonConvert.DeserializeObject<cargaFirebase>(resp.Body);

这给了我一个我无法理解的反序列化错误,没有真正进入 jsons 抱歉,谢谢!

Newtonsoft.Json.JsonSerializationException: 无法将当前 JSON 对象(例如 "name":"value")反序列化为类型 'System.Collections.Generic.List`1[Reparto_Android.Code.Helpers.FirebaseHelper+documentoFirebase ]' 因为 该类型需要一个 JSON 数组(例如 [1,2,3])才能正确反序列化。 要修复此错误,要么将 JSON 更改为 JSON 数组(例如 [1,2,3]),要么将反序列化类型更改为普通的 .NET 类型(例如,不是像整数这样的原始类型,而不是像这样的集合类型可以从 JSON 对象反序列化的数组或列表。 JsonObjectAttribute 也可以添加到类型中以强制它从 JSON 对象反序列化。 路径

【问题讨论】:

这些属性中没有一个是正确的。您没有 Cobros、Pedidos 或 Repartidores 的列表,它们都是单个对象 - 正如异常消息告诉您的那样:“要修复此错误,请将 JSON 更改为 JSON 数组(例如 [1,2,3])或更改反序列化类型,使其成为可以从 JSON 反序列化的普通 .NET 类型(例如,不是整数之类的原始类型,不是数组或列表之类的集合类型)对象。” 【参考方案1】:

这段代码可以正常工作

cargaFirebase carga_res = JsonConvert.DeserializeObject<CargaFirebase>(resp.Body);

如果你使用这些类

 public partial class CargaFirebase
    
        [JsonProperty("Cobros")]
        public Dictionary<string, Cobro> Cobros  get; set; 

        [JsonProperty("Pedidos")]
        public Pedidos Pedidos  get; set; 

        [JsonProperty("Repartidores")]
        public Dictionary<string, Repartidore> Repartidores  get; set; 
    

    public partial class Cobro
    
        [JsonProperty("Estado")]
        public string Estado  get; set; 

        [JsonProperty("Repartidor")]
        public long Repartidor  get; set; 
    

    public partial class Pedidos
    
        [JsonProperty("1111")]
        public Cobro The1111  get; set; 
    

    public partial class Repartidore
    
        [JsonProperty("ID Android")]
        public string IdAndroid  get; set; 

        [JsonProperty("Terminal")]
        public long Terminal  get; set; 
    

输出


  "Cobros": 
    "1001": 
      "Estado": "Cobrado",
      "Repartidor": 124
    ,
    "1112": 
      "Estado": "Pendiente",
      "Repartidor": 124
    
  ,
  "Pedidos": 
    "1111": 
      "Estado": "Entregado",
      "Repartidor": 123
    
  ,
  "Repartidores": 
    "123": 
      "ID Android": "asdadada",
      "Terminal": 123
    ,
    "124": 
      "ID Android": "dggrefawe",
      "Terminal": 124
    
  

【讨论】:

【参考方案2】:

如果所有这些叶子名称,例如“1111”、“1001”、“1112”,都是动态生成的,而您想忽略它们,也许您可​​以尝试一些自定义的 json 转换器,如下所示:

public class CargaFirebase

    [JsonConverter(typeof(DocumentoFirebaseConverter))]
    public List<DocumentoFirebase> Cobros  get; set;

    [JsonConverter(typeof(DocumentoFirebaseConverter))]
    public List<DocumentoFirebase> Pedidos  get; set;

    [JsonConverter(typeof(RepartidorFirebaseConverter))]
    public List<RepartidorFirebase> Repartidores  get; set; 



public class DocumentoFirebase

    public string Estado  get; set; 
    public int Repartidor  get; set; 


public class RepartidorFirebase

    [JsonProperty(PropertyName = "Id Android")]
    public string Id_Android  get; set; 
    public int Terminal  get; set; 


class DocumentoFirebaseConverter : JsonConverter

    public override bool CanConvert(Type objectType)
    
        return objectType == typeof(List<DocumentoFirebase>);
    

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    
        var jObj = JObject.Load(reader);
        List<DocumentoFirebase> docs = new List<DocumentoFirebase>();
        foreach (JProperty prop in jObj.Properties())
        
            var doc = prop.Value.ToObject<DocumentoFirebase>();
            docs.Add(doc);
        
        return docs;
    

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


class RepartidorFirebaseConverter : JsonConverter

    public override bool CanConvert(Type objectType)
    
        return objectType == typeof(List<RepartidorFirebase>);
    

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    
        var jObj = JObject.Load(reader);
        List<RepartidorFirebase> repartidors = new List<RepartidorFirebase>();
        foreach (JProperty prop in jObj.Properties())
        
            var repartidor = prop.Value.ToObject<RepartidorFirebase>();
            repartidors.Add(repartidor);
        
        return repartidors;
    

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

然后你可以尝试像之前那样解析原始 json:

cargaFirebase carga_res = JsonConvert.DeserializeObject<CargaFirebase>(resp.Body);

【讨论】:

以上是关于如何将 JSON 反序列化为具有多个 List<T> 参数的 .NET 对象?的主要内容,如果未能解决你的问题,请参考以下文章

如何将具有嵌套属性的 JSON 对象反序列化为 Symfony 实体?

JSON.Net - 无法将当前 json 对象(例如 "name":"value")反序列化为类型 'system.collections.generic.l

如何将具有不同值的相同 JSON 对象反序列化为 java 类

如何将多个键值条目的 JSON 对象反序列化为 Rust 中的自定义结构

将 JSON 数组反序列化为 List<T> C# 时出错

使用 Json.NET 将异构 JSON 数组反序列化为协变 List<>