【问题标题】:How to deserialize a nested json object into a primitive type based on one of the nested object's field如何根据嵌套对象的字段之一将嵌套的 json 对象反序列化为原始类型
【发布时间】:2020-02-10 22:30:16
【问题描述】:

假设我有这段 json:

[{
    "id": 123,
    "description": "test",
    "group": {
        "id": 456,
        "description": "org"
    }
}]

我想将上面的 JObject 反序列化为 C# 对象。传统上我已经解决了这样的问题(其中 jObject 是从上面的 json 字符串加载的 JObject):

public class Item
{
    [JsonProperty("id")]
    public int Id { get; set; }

    [JsonProperty("description")]
    public string Description { get; set; }

    [JsonProperty("group")]
    public Group Group { get; set; }

}

public class Group
{
    [JsonProperty("id")]
    public int Id { get; set; }

    [JsonProperty("description")]
    public string Description { get; set; }

}

var foo = jObject.ToObject<Item>();

如果在 Item 类中,我只想有一个名为 GroupId 的 int 类型的字段,它只存储嵌套 Group 对象中的 id 字段怎么办?创建一个方法来将该值提取到 Item 中名为“GroupId”的字段中会很简单,但是因为我正在处理的 json 有很多类似的嵌套对象,我只对 id 感兴趣,所以我想知道我是否可以使用 JsonSerializer 类在反序列化时以某种方式自动完成填充“GroupId”字段?或者如果我可能不知道 Newtonsoft.Json 包中还有另一种方法。

我还没有广泛地处理 Json,所以如果这是 100 级的东西,我很抱歉;我找不到任何直接专门解决这个问题的东西。

【问题讨论】:

    标签: c# json


    【解决方案1】:

    由于您使用的是Newtonsoft.Json,我将使用相同的解释。

    当我需要获取仅用于我的逻辑的 JSON 时,我倾向于这样做:

    对于您的 Item 类,您想做两件事。一、不必每次都手动设置。二,没有由于该值未被识别或其他原因导致任何序列化失败。

    第一步是使用表达式主体。这基本上会使您想要充当简单方法的属性,但就像属性一样工作。第二步就是简单的添加[JsonIgnore]属性:

    所以你的 Item 类变成了这样:

    public class Item
        {
            /// <summary>
            /// Property that will be left out of deserialization, but return the Group.Id every time the value is
            /// evaluated.
            /// </summary>
            [JsonIgnore]
            public int GroupId => (int)Group?.Id;
    
            [JsonProperty("id")]
            public int Id { get; set; }
    
            [JsonProperty("description")]
            public string Description { get; set; }
    
            [JsonProperty("group")]
            public Group Group { get; set; }
        }
    

    请注意现在属于 items 类的“GroupId”属性。 “Group”属性后面的问号将确保 Group 对象在尝试评估 id 属性之前不为空。

    使用上面的 JSON,我自己在单元测试中对此进行了测试:

    如果您需要有关上述任何内容的更多信息,请告诉我。

    【讨论】:

    • 完美运行!
    【解决方案2】:

    您应该使用如下语句:
    var foo = Newtonsoft.Json.JsonConvert.DeserializeObject>(jObject.ToString());

    第一点是JSON看起来像一个对象数组,所以你应该在解析的时候像List这里使用集合。

    你可以使用jobject,但在这种情况下,你需要在这里将它转换为字符串,如jObject.ToString(),或者你可以将JSON字符串直接传递给函数。

    之后,您可以通过索引获取 Group Id 值,例如:-
    var GroupId = foo[0].Group.Id;

    【讨论】:

      【解决方案3】:

      如果要将group JSON 对象转换为单个值,并将其分配给属性,则可以使用自定义 JsonConverter。

      在这里,自定义ObjectToValueConverter 被分配给GroupId 属性,并用[JsonProperty("group")] 装饰。当group对应的对象被反序列化时,调用自定义转换,它会返回对象的id属性的Value,如果存在,转换为int。否则0

      Group 类不再使用:

      var myItems = JsonConvert.DeserializeObject<List<Item>>(json);
      

      如果您更愿意保留 Group 类对象,请执行 Kuroiyatsu 的建议。


      public class Item
      {
          [JsonProperty("id")]
          public int Id { get; set; }
      
          [JsonProperty("description")]
          public string Description { get; set; }
      
          [JsonProperty("group")]
          [JsonConverter(typeof(ObjectToValueConverter))]
          public int GroupId { get; set; }
      }
      
      class ObjectToValueConverter : JsonConverter
      {
          public override bool CanConvert(Type objectType) => true;
      
          public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
          {
              var token = JToken.Load(reader);
              if (token.Type == JTokenType.Object && ((JObject)token).ContainsKey("id")) {
                  return (int)token["id"];
              }
              return 0;
          }
      
          public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
              => throw new NotImplementedException();
      }
      

      【讨论】:

      • 这是一个很好的解决方案,但我也有兴趣保留类对象。
      • 当然。我发布它是因为缺少此选项。它在其他一些场景中可能很有用。
      猜你喜欢
      • 1970-01-01
      • 2017-12-28
      • 2016-12-12
      • 2017-12-28
      • 1970-01-01
      • 2017-10-29
      • 2019-07-09
      • 1970-01-01
      相关资源
      最近更新 更多