Search code examples
c#jsonjsonconvert

How to search polymorphic JSON objects in c#?


Deserializing the following json

{
    "MetaData1": "hello world",
    "MetaData2": 2022,
    "Data": {
        "ObjectA": {
            "id": 1,
            "name": "steve",
            "hobbies": 1
        },
        "ObjectB": {
            "id": 2,
            "name": "dave",
            "age": 55
        }
    }
}

into corresponding c# objects

public class ObjectBase
{
    public int id { get; set; }
    public string name { get; set; }

}
public class ObjectA : ObjectBase
{
    public int hobbies { get; set; }
}

public class ObjectB : ObjectBase
{
    public int age { get; set; }
}

public class Data
{
    public ObjectA ObjectA { get; set; }
    public ObjectB ObjectB { get; set; }
}

public class Root
{
    public string metaData1 { get; set; }
    public int metaData2 { get; set; }
    public Data Data { get; set; }
}

using

Root object = JsonConvert.DeserializeObject<Root>(json);

How could I search the id properties of the object properties of Root.Data for a matching int and return the corresponding name property.

It would also be useful to be able to create List<ObjectBase> so that other LINQ operations could be performed on these objects.


Solution

  • i think what i am ultimately after here is to end up with List<ObjectBase>.

    This can be achieved easily with System.Text.Json (or Newtonsoft).

    The most natural representation (IMO) given your Json structure would be to deserialize into a Dictionary<string, ObjectBase>. Then you could convert the dictionary to a List<ObjectBase>. You need a class to match the Data element in your (updated) Json:

    // 'root' class to represent the 'Data' element
    public class Root
    {
        public string MetaData1 { get; set; }
        public int MetaData2 { get; set; }
        public Dictionary<string, ObjectBase> Data { get; set; }
    }
    
    // Dictionary<string, ObjectBase>
    var model = JsonSerializer.Deserialize<Root>(json);
    foreach (var key in model.Data.Keys)
        // do something with model.Data[key].id/name
    
    // convert to List<ObjectBase>
    var list = new List<ObjectBase>(model.Data.Values);
    

    Expanding on Lasse V. Karlsen's comment, you could instead add all properties to a single class and deserialize into a Dictionary<string, SingleClass>:

    public class SingleClass
    {
        public int id { get; set; }
        public string name { get; set; }
        public int hobbies { get; set; }
        public int age { get; set; }
        // all other properties...
    }
    

    If you choose this method you may want to consider making the additional properties nullable (if you're interested in differentiating between no hobbies property or someone with hobbies = 0, for example).

    The methods above will deserialize into either ObjectBase or the SingleClass.

    Demo online