简体   繁体   中英

Json to C# object handling dynamic properties

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': []
                }
            }
        }";

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

如果要反序列化为带有 Key 字符串和动态值(在这种情况下是男孩或女孩)的字典,我知道的唯一方法是使用 Dynamic 类:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM