Json to C#对象处理动态属性

时间:2019-04-08 08:44:57

标签: c# json json.net

我试图在c#对象中实现json结构,并且试图了解如何根据类型使用正确的对象。例如:

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;}
}

请注意,这只是一个示例,每个对象都有更多的属性。如果Json包含type =“ Boy”,我该如何生成男孩对象。

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

2 个答案:

答案 0 :(得分:1)

如果您的键/值对不是固定的,并且数据必须可配置,则Newtonsoft.json具有一项要在此处使用的功能,即 [JsonExtensionData] Read more < / p>

  

现在,序列化对象时将写入扩展数据。读取和写入扩展数据可以自动往返所有JSON,而无需将所有属性添加到要反序列化的.NET类型。仅声明您感兴趣的属性,然后让扩展数据完成其余工作。

在您的情况下,假设有一个课程,

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

在上面的类中,您知道QazWsx始终存在于您的json中,它们包含value或null,

但是对于动态数据,您无法说出将从json接收到哪个键/值对,因此[JsonExtensionData]可以将所有这些键/值对收集到字典中。

假设以下类别适用于您的动态数据,

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

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

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

序列化:

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

这会给你像json

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

反序列化:

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

结论 [JsonExtensionData] 的主要目的是使json类层次结构保持简单和可读性,因此您无需为每个属性。

使用Dictionary中的JToken中的特定键获取所有动态数据:

您可以使用LINQ从上述字典中获取特定键的所有动态数据。

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

在您的情况下,类似

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

答案 1 :(得分:0)

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

ui <- fluidPage(
  dashboardPage(
    dashboardHeader(),
    dashboardSidebar(width = 0),
    dashboardBody(
      fluidRow(
        box(plotOutput("plot1", height = 400), width = 12) 
      )
    )
  )
)