【问题标题】:Deserialize different json property to same model property conditionally有条件地将不同的 json 属性反序列化为相同的模型属性
【发布时间】:2018-03-30 10:49:21
【问题描述】:

假设我有以下 json。

{
   "allitemscount":2,
   "allitems":[
        {"itemid":"1","itemname":"one"}, 
        {"itemid":"2","itemname":"two"}],
   "customitems":[
       {"itemid":"3","itemname":"three"}, 
       {"itemid":"4","itemname":"four"}]
}

当反序列化这个json时,它应该去下面的C#模型。

public class response
{
  public int allitemscount;
  public List<item> items;
}

public class item
{
   public string itemid;
   public string itemname;
}

问题: 如何根据条件在allitemscustomitems 之间切换?例如,如果useAllitems 为真,则来自json 的allitems 将填写在项目中,如果useCustomItems 为真,customitems 将在项目属性中填写。请帮助了解如何执行此操作。

public List&lt;item&gt; items 上使用JsonProperty 允许在allitems 之间切换,但是有没有办法根据上述条件进行反序列化。

【问题讨论】:

  • 您是从应用程序内部还是从 json 获得条件?
  • 来自应用程序...
  • 检查我的答案只是从应用程序传递参数。它应该干净利落。
  • 你有没有尝试实现我的回答伙伴?
  • 是的......它就像小菜一碟......

标签: c# json deserialization json-deserialization


【解决方案1】:

我是通过编写我们自己的继承自 JsonConverter 的 ItemConverter 来实现的,

我在尝试中使用的示例模型 json:

{
  "allitemscount": 2,
  "UseCustomItems": true,
  "allitems": [
    {
      "itemid": "1",
      "itemname": "one"
    },
    {
      "itemid": "2",
      "itemname": "two"
    }
  ],
  "customitems": [
    {
      "itemid": "3",
      "itemname": "three"
    },
    {
      "itemid": "4",
      "itemname": "four"
    }
  ]
}

控制台应用的main方法:

static void Main(string[] args)
{
    using (StreamReader r = new StreamReader(@"\model.json")) // json path
    {
        string json = r.ReadToEnd();

        var deserializedJson = JsonConvert.DeserializeObject<Result>(json, new ItemConverter());
    }
}

型号:

public class Result // main object
{
    [JsonProperty("allitemscount")]
    public long Allitemscount { get; set; }

    public bool UseCustomItems { get; set; }
}

public class ResultA : Result // CustomItems Model
{
    [JsonProperty("customitems")]
    private List<Item> Items { get; set; }
}

public class ResultB : Result // AllItems Model
{
    [JsonProperty("allitems")]
    private List<Item> Items { get; set; }
}

public class Item
{
    [JsonProperty("itemid")]
    public string Itemid { get; set; }

    [JsonProperty("itemname")]
    public string Itemname { get; set; }
}

以及我们在反序列化为对象时使用的 ItemConverter:

internal class ItemConverter : JsonConverter
{
    private Type currentType;

    public override bool CanConvert(Type objectType)
    {
        return typeof(Item).IsAssignableFrom(objectType) || objectType == typeof(Result);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject item = JObject.Load(reader);
        if (item["UseCustomItems"] != null)
        {
            // save the type for later.
            switch (item["UseCustomItems"].Value<bool>())
            {
                case true:
                    currentType = typeof(ResultA);
                    return item.ToObject<ResultA>(); // return result as customitems result
                case false:
                    currentType = typeof(ResultB);
                    return item.ToObject<ResultB>(); // return result as allitems result
            }
            return item.ToObject<Result>();
        }

        // use the last type you read to serialise.
        return item.ToObject(currentType);
    }

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

结果应该像下面的图片

希望这个解决方案对你有所帮助

【讨论】:

    【解决方案2】:

    您可以通过如下更改 response 类来反序列化上述 json,

    public class response{
          public int allitemscount;
          public List<item> allitems;
          public List<item> customitems;    
    }
    

    然后使用下面的代码,

    var jsonData = "{\"allitemscount\":2,   \"allitems\":[{\"itemid\":\"1\",\"itemname\":\"one\"}, {\"itemid\":\"2\",\"itemname\":\"two\"}],\"customitems\":[{\"itemid\":\"3\",\"itemname\":\"three\"},{\"itemid\":\"4\",\"itemname\":\"four\"}]}";
    
    var data = JsonConvert.DeserializeObject<response>(jsonData);
    foreach(var str in data.allitems) {
              Console.WriteLine(str.itemid +'-'+str.itemname);
    }
    foreach(var str in data.customitems) {
              Console.WriteLine(str.itemid +'-'+str.itemname);
    }
    

    【讨论】:

    • 应用程序已经在使用项目集合,并且不想通过引入更多集合来进行太多更改。我认为更简洁的解决方案是将 customjsondata 读入同一个集合。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多