从C#中的引用ID反序列化JSON对象

时间:2019-02-18 15:40:11

标签: c# json json.net deserialization

我在json中有一个项目列表

"items":[
      {
        "id": 0,
        "name": "Thats a name",
        "type": 0,
        "price": 3.5,
        "ingredients": [1,0,2,3],
      },
      {
        "id": 1,
        "name": "This is AnotherName",
        "type": 0,
        "price": 3.7,
        "ingredients": [5,0,6,10,2,8],
      }
]

typeingredients属性在同一JSON文件的另一个对象中详细说明。如果我查找一下,我就会知道0型是什么,成分是什么。

在c#中,我要实现的目标是使我的数据模型没有到处都有int,而是有实际的对象。例如,使用成分,我的Item对象具有Ingredients类型的List<Ingredient>属性,并且不是 List<int>

类似于以下内容:

public IEnumerable<Ingredient> Ingredients { get; set; }
public IEnumerable<FoodType> Types { get; set; }
public IEnumerable<FoodItem> Items { get; set; }


public class FoodItem
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Type { get; set; }
    public float Price { get; set; }
    public IEnumerable<Ingredient> Ingredients { get; set; }
}

但是在我反序列化的当前状态下,它崩溃了,因为它正在寻找一个整数。

我找到了有关“ PreserveReferenceHandling”或“ isReference”的关键字,但没有真正的帮助,但我不确定它们是什么,甚至不确定如何使用它们。

这是我反序列化的方式:

var json = r.ReadToEnd();
var items = JsonConvert.DeserializeObject<EatupDataModel>(json);

我知道以下方法会起作用:

  • 更改json文件,使其包含实际对象,而不包含ID
  • 更改数据模型以使用int而不是对象

但是我会非常非常喜欢不要这样做,第一个需要疯狂的繁琐工作,而另一个则迫使我拥有两个几乎相同的对象版本,然后在两者之间映射属性。这似乎很愚蠢,当然我不能成为第一个面对这个问题的人。

我该怎么做才能实现自己的目标?

1 个答案:

答案 0 :(得分:2)

You will want to clean this up a bit. But should give you a proof of concept on how to do create your custom converter.

public class Item
{
    public int id { get; set; }
    public string name { get; set; }
    public int type { get; set; }
    public double price { get; set; }
    [JsonConverter(typeof(KeysJsonConverter))]
    public List<Ingredient> ingredients { get; set; }
}

public class RootObject
{
    public List<Item> items { get; set; }
}
public class KeysJsonConverter : JsonConverter
{      
    public KeysJsonConverter()
    {

    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
    throw new NotImplementedException("Unnecessary because CanWrite is false. The type will skip the converter.");

    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var ingredientsList = new List<Ingredient>();

        if (reader.TokenType != JsonToken.Null)
        {
            if (reader.TokenType == JsonToken.StartArray)
            {
                JToken token = JToken.Load(reader);
                List<int> items = token.ToObject<List<int>>();
                ingredientsList = items.Select(x => IngredientList.Ingredients.FirstOrDefault(y => y.Id == x)).ToList();
            }
        }
        return ingredientsList;
    }

    public override bool CanRead
    {
        get { return true; }
    }
   public override bool CanWrite
    {
        get { return false; }
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(object[]);
    }
}
public static class IngredientList
{
    public static List<Ingredient> Ingredients = new List<Ingredient>()
    {
        new Ingredient()
        {
            Id = 1,
            Name = "Test 1"
        },
        new Ingredient()
        {
            Id = 2,
            Name = "Test 2"
        }
    };
}
public class Ingredient{
    public string Name { get; set; }
    public int Id { get; set; }
}