有条件地将不同的json属性反序列化为相同的模型属性

时间:2018-03-30 10:49:21

标签: c# json deserialization json-deserialization

假设我有以下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<item> items上使用JsonProperty允许在allitems之间切换,但有没有办法根据上述条件进行反序列化。

2 个答案:

答案 0 :(得分:2)

我编写了自己的继承自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"
    }
  ]
}

控制台应用程序的主要方法:

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();
    }
}

结果应该像下面的图像 enter image description here

我希望此解决方案对您有所帮助

答案 1 :(得分:0)

您可以通过更改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);
}