Search code examples
c#.netjsonjson.net

Map properties to a list of objects


I have a JSON data that looks like this:

{
    "Item1": {
        "Field1": "Val1",
        "Field2": "Val2"
    },
    "Item2": {
        "Field1": "Val11",
        "Field2": "Val22"
    },
    ....
    "ItemN": {
        "Field1": "Val1",
        "Field2": "Val2"
    },
}

I need to deserialize it to a set of classes that look like this:

public class Root
{
    public Item Item1;
    public Item Item2;

    public List<Item> Items; // << all the Items should go here
}

public class Item
{
    public string Field1;
    public string Field2;
}

How can I make Newtonsoft.Json to map data this way when deserializing?


Solution

  • If you need to populate the Items list and the individual Item properties shown in your Root class from the same data in the JSON, then you will need a custom JsonConverter to do it. The following converter should work:

    public class RootConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return objectType == typeof(Root);
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            JObject obj = JObject.Load(reader);
            var root = new Root();
    
            // populate all known Root properties 
            serializer.Populate(obj.CreateReader(), root);
    
            // populate Items list with all objects that can be converted to an Item
            root.Items = obj.Properties()
                            .Where(p => p.Value.Type == JTokenType.Object && 
                                        (p.Value["Field1"] != null || p.Value["Field2"] != null))
                            .Select(p => p.Value.ToObject<Item>())
                            .ToList();
            return root;
        }
    
        public override bool CanWrite
        {
            get { return false; }
        }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
    }
    

    Then to use it, add a [JsonConverter] attribute to your Root class like this:

    [JsonConverter(typeof(RootConverter))]
    public class Root
    {
        public Item Item1 { get; set; }
        public Item Item2 { get; set; }
    
        public List<Item> Items; // << all the Items should go here
    }
    

    Fiddle: https://dotnetfiddle.net/aADhzw