4

I am trying to implement the json structure in c# objects and I am trying to understand how I can use the correct object depending on the type. For example:

public class RootObject
{
    public string name { get; set; }
    public Content content { get; set; }

}
public class Content
{
    public string id{ get; set; }
    public string type { get; set; }
    public Dictionary<string, Item> child { get; set; }
}

public class Item
{
    public string id { get; set; }
    public string type { get; set; }
    public List<string> model { get; set;}
    public string[] color {get; set;}
}

Please note this is just an example there are more properties for each object. If Json contains type = "Boy" how can I generate the boy object.

Example JSON:

string json = @"
            {
            'name': 'Object 1',
            'content': {
                'body': {
                    'id': 'body',
                    'type': 'Body'
                },
                'style': {
                    'id': 'style',
                    'type': 'Style'
                },
                'DynamicName-123': {
                    'id': 'DynamicName-123',
                    'type': 'Row'
                    'model': {},
                    'colors': []
                },
                'DynamicName-434': {
                    'id': 'DynamicName-434',
                    'type': 'Column'
                    'model': {},
                    'colors': []
                },
                'DynamicName-223': {
                    'id': 'DynamicName-223',
                    'type': 'Item'
                    'model': {},
                    'colors': []
                }
            }
        }";
10
  • Can you change the generated json to include the type, or is it data you are receiving? In case you can't change it, I think you might have to implement your own custom JsonConverter and overwrite the read method based on properties Commented Apr 8, 2019 at 8:48
  • Yes the json includes type in the json and also Id which is static. @Icepickle Commented Apr 8, 2019 at 8:53
  • 2
    Please read How to Ask and show what you have tried. Also, create a minimal reproducible example including some example JSON. See for example How to deserialize a JSON array containing different data types to a single object. You probably need a custom JsonConverter that instantiates the appropriate type depending on the type string in the JSON. Commented Apr 8, 2019 at 8:54
  • Any chance you can share a json sample? Commented Apr 8, 2019 at 8:56
  • Could you please show your json to get clear idea about you tried to do so? Commented Apr 8, 2019 at 9:07

2 Answers 2

3

If your key/value pair are not fixed and data must be configurable then Newtonsoft.json has one feature that to be use here and that is [JsonExtensionData] Read more

Extension data is now written when an object is serialized. Reading and writing extension data makes it possible to automatically round-trip all JSON without adding every property to the .NET type you’re deserializing to. Only declare the properties you’re interested in and let extension data do the rest.

In your case, suppose there is a class,

public class MyClass
{
    public string Qaz { get; set; }
    public string Wsx { get; set; }

    [JsonExtensionData]
    public Dictionary<string, JToken> child { get; set; }

    public MyClass()
    {
        child = new Dictionary<string, JToken>();
    }
}

In the above class, you know that Qaz and Wsx are always present from your json either they contain value or null,

But for dynamic data, you can't say which key/value pair you will receive from your json so the [JsonExtensionData] can collect all those key/value pair in a dictionary.

Suppose the below classes will be for your dynamic data,

public class ABC
{
    public string Abc { get; set; }
}

public class PQR
{
    public string Pqr { get; set; }
}

public class XYZ
{
    public string Xyz { get; set; }
}

Serialization:

ABC aBC = new ABC { Abc = "abc" };
PQR pQR = new PQR { Pqr = "pqr" };
XYZ xYZ = new XYZ { Xyz = "xyz" };

MyClass myClass = new MyClass();

myClass.Qaz = "qaz";
myClass.Wsx = "wsx";

myClass.child.Add("ABC", JToken.FromObject(aBC));
myClass.child.Add("PQR", JToken.FromObject(pQR));
myClass.child.Add("XYZ", JToken.FromObject(xYZ));

string outputJson = JsonConvert.SerializeObject(myClass);

This will give you json like

{
  "Qaz": "qaz",
  "Wsx": "wsx",
  "ABC": {
    "Abc": "abc"
  },
  "PQR": {
    "Pqr": "pqr"
  },
  "XYZ": {
    "Xyz": "xyz"
  }
}

Deserialization:

MyClass myClass = JsonConvert.DeserializeObject<MyClass>(outputJson);

string Qaz = myClass.Qaz;
string Wsx = myClass.Wsx;

if (myClass.child.ContainsKey("ABC"))
{
    ABC abcObj = myClass.child["ABC"].ToObject<ABC>();
}

if (myClass.child.ContainsKey("PQR"))
{
    PQR pqrObj = myClass.child["PQR"].ToObject<PQR>();
}

if (myClass.child.ContainsKey("XYZ"))
{
    XYZ pqrObj = myClass.child["XYZ"].ToObject<XYZ>();
}

Conclusion: The main aim of [JsonExtensionData] is to keep your json class hierarchy simple and more readable so you don't need to manage class structure for every property.

Get all dynamic data with the specific key in JToken inside Dictionary :

You can use LINQ to fetch all dynamic data of particular key from the above dictionary.

var allAbcTypes = myClass.child
    .SelectMany(x => x.Value
                      .ToObject<JObject>()
                      .Properties()
                      .Where(p => p.Name == "Abc")    //<= Use "Column" instead of "Abc"
                      .Select(o => new ABC            //<= Use your type that contais "Column" as a property
                      {
                           Abc = o.Value.ToString()
                      })).ToList();

In your case, Its something like,

var allColumnTypes = myClass.child
    .SelectMany(x => x.Value
                      .ToObject<JObject>()
                      .Properties()
                      .Where(p => p.Name == "Column")
                      .Select(o => new Item
                      {
                         id = x.Value["id "].ToString(),
                         type = x.Value["type "].ToString(),
                         model = x.Value["model"].ToObject<List<string>>(),
                         color = x.Value["color"].ToObject<string[]>()
                      })).ToList();
Sign up to request clarification or add additional context in comments.

12 Comments

If I wanted to output lets say all boy objects how can I do that? I can call on the type or id however object name is dynamic
let me know how much boy objects available in your json because on same level json doesn't allow you to add same key with multiple times, please show your sample json to get clear idea that clarify what you want to do?
I have updated the thread with an example. I am simply trying to generate a list of objects like the structure above but in my chase each object has a unique name but properties are the same. I cant exactly call [Jsonproperty()] as it is always unique
Your class structure that you updated now is already for unique name for your json showed because you already use Dictionary and this dictionary will handle unique name because dictionary will not permit for duplicate key name except that you have to remove id and type from Content class. And then everything will work for you
Or I think you want to know that how you populate object that generate the json that you showed in post?
|
0

If you want to deserialize to a dictionary with a Key string and a dynamic value (boy or girl in this case), the only way I Know is using Dynamic class:

 public List<Dictionary<string, dynamic>> child { get; set; }

2 Comments

Ah interesting this might be the solution I need as I dont really care about the Json I am deserializing I simply want to store it and extract data from it. How would I access this data?
You can use it like other class: var dynamic = new Boy(); Console.WriteLine(dynamic.Name) But in your case, maybe the best option is cast the object (I not sure what you're going to do with this, but I write you an example): if (element is Boy) { var boy = element as Boy; Your Code in Boy's cases } else if (element is Girl) { var girl = element as Girl; Your code in Girls' cases} If other cases where you just want serialize the object the best option is JTOKEN like er-ho saids.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.