使用Json.NET,如何将具有动态名称的对象列表解析为List?

时间:2021-05-13 15:56:25

Below is an example of the JSON format I'm receiving from an external API:

下面是我从外部API接收的JSON格式的示例:

"object": {
  "property_1": {
    "values": {
      "value": 1,
      "displayValue": "1"
    }
  },
  "property_5": {
    "values": {
      "value": 3,
      "displayValue": "3"
    }
  },
  "property_8": {
    "values": {
      "value": 1,
      "displayValue": "1"
    }
  },
  "property_14": {
    "values": {
      "value": 392,
      "displayValue": "392.0"
    }
  },
  "property_17": {
    "values": {
      "value": 14,
      "displayValue": "14"
    }
  }
}

There are somewhere around 100 different property types that can be sent, but they all follow the same structure. The only distinction is the name of the property ("property_1", "property_5", etc). Rather than attempting to write a class with a long list of properties that are not always used, I think it'd be much more useful to parse this into a list of objects, using the property name in the resulting class like so:

有大约100种不同的属性类型可以发送,但它们都遵循相同的结构。唯一的区别是属性的名称(“property_1”,“property_5”等)。我没有尝试使用一长串不常用的属性来编写一个类,而是认为将它解析为一个对象列表会更有用,使用结果类中的属性名称,如下所示:

public class Property
{
    public string Name { get; set; }
    public PropertyValues Values { get; set; }
}

public class PropertyValues
{
    public double Value { get; set; }
    public string DisplayValue { get; set; }
}

In this case, the property name ("property_1", "property_5", etc) would be assigned to the Name field of the Property object.

在这种情况下,属性名称(“property_1”,“property_5”等)将分配给Property对象的Name字段。

How can this be accomplished using Json.NET?

如何使用Json.NET实现这一目标?

2 个解决方案

#1


10  

var result  = JsonConvert.DeserializeObject<Root>(json);

You model is below

你的模特在下面


public class Root
{
    public Dictionary<string, ValueWrapper> Object { get; set; }
}
public class ValueWrapper
{
    public PropertyValues Values { get; set; }
}

public class PropertyValues
{
    public int Value { get; set; }
    public string DisplayValue { get; set; }
}

BTW: Json.Net can handle dynamic more easily than proposed by @MatíasFidemraizer...

BTW:Json.Net可以比@MatíasFidemraizer提出的更容易处理动态...

var val = ((dynamic)JsonConvert.DeserializeObject(jsonstring))
          .@object.property_14.values.value;

var val = ((dynamic)JsonConvert.DeserializeObject(jsonstring))
          .@object["property_14"].values.value;

But this approach would require you to know property_14 will be returned by your server beforehand...

但是这种方法需要你知道你的服务器会事先返回property_14 ...

#2


2  

There's even another approach: you can use expando objects:

还有另一种方法:你可以使用expando对象:

dynamic response = JsonConvert.DeserializeObject<ExpandoObject>("JSON TEXT", new ExpandoObjectConverter());

And you can access properties using dynamic typing:

您可以使用动态类型访问属性:

long someValue = response.@object.property_1.values.value;

Also, since ExpandoObject implements IDictionary<string, object>, you can use it like a dictionary and check if a property exists:

此外,由于ExpandoObject实现了IDictionary ,您可以像字典一样使用它并检查属性是否存在: ,object>

if(((IDictionary<string, object>)response.@object).ContainsKey("property_1"))
{

}

It seems like you're going to save a lot of time going this way!

看起来你会节省很多时间这样的方式!

Answering hate on this answer

It seems like the most hate on my answer is focused on this @EZI comment:

似乎对我的回答最讨厌的是关注@EZI的评论:

And suppose you don't know property_14 before deserializing the json..

并且假设在反序列化json之前你不知道property_14 ..

And the other answerer @L.B argues this on his own answer:

另一个回答者@ L.B在他自己的回答中提出这个问题:

But this approach would require you to know property_14 will be returned by your server beforehand...

但是这种方法需要你知道你的服务器会事先返回property_14 ...

In my case, I find that this concern is already addressed in my answer when I mention that ExpandoObject implements IDictionary<string, object>. Perhaps you don't know that property_14 will be part of deserialized object graph. No problem:

在我的例子中,当我提到ExpandoObject实现IDictionary 时,我发现在我的回答中已经解决了这个问题。也许您不知道property_14将成为反序列化对象图的一部分。没问题: ,object>

if(((IDictionary<string, object>)response.@object).ContainsKey("property_14"))
{
    // You've already addressed the issue, because you won't get a 
    // run-time exception since you'll access such property if it's already
    // in the returned response...
    object property_14 = response.@object.property_14;
}

#1


10  

var result  = JsonConvert.DeserializeObject<Root>(json);

You model is below

你的模特在下面


public class Root
{
    public Dictionary<string, ValueWrapper> Object { get; set; }
}
public class ValueWrapper
{
    public PropertyValues Values { get; set; }
}

public class PropertyValues
{
    public int Value { get; set; }
    public string DisplayValue { get; set; }
}

BTW: Json.Net can handle dynamic more easily than proposed by @MatíasFidemraizer...

BTW:Json.Net可以比@MatíasFidemraizer提出的更容易处理动态...

var val = ((dynamic)JsonConvert.DeserializeObject(jsonstring))
          .@object.property_14.values.value;

var val = ((dynamic)JsonConvert.DeserializeObject(jsonstring))
          .@object["property_14"].values.value;

But this approach would require you to know property_14 will be returned by your server beforehand...

但是这种方法需要你知道你的服务器会事先返回property_14 ...

#2


2  

There's even another approach: you can use expando objects:

还有另一种方法:你可以使用expando对象:

dynamic response = JsonConvert.DeserializeObject<ExpandoObject>("JSON TEXT", new ExpandoObjectConverter());

And you can access properties using dynamic typing:

您可以使用动态类型访问属性:

long someValue = response.@object.property_1.values.value;

Also, since ExpandoObject implements IDictionary<string, object>, you can use it like a dictionary and check if a property exists:

此外,由于ExpandoObject实现了IDictionary ,您可以像字典一样使用它并检查属性是否存在: ,object>

if(((IDictionary<string, object>)response.@object).ContainsKey("property_1"))
{

}

It seems like you're going to save a lot of time going this way!

看起来你会节省很多时间这样的方式!

Answering hate on this answer

It seems like the most hate on my answer is focused on this @EZI comment:

似乎对我的回答最讨厌的是关注@EZI的评论:

And suppose you don't know property_14 before deserializing the json..

并且假设在反序列化json之前你不知道property_14 ..

And the other answerer @L.B argues this on his own answer:

另一个回答者@ L.B在他自己的回答中提出这个问题:

But this approach would require you to know property_14 will be returned by your server beforehand...

但是这种方法需要你知道你的服务器会事先返回property_14 ...

In my case, I find that this concern is already addressed in my answer when I mention that ExpandoObject implements IDictionary<string, object>. Perhaps you don't know that property_14 will be part of deserialized object graph. No problem:

在我的例子中,当我提到ExpandoObject实现IDictionary 时,我发现在我的回答中已经解决了这个问题。也许您不知道property_14将成为反序列化对象图的一部分。没问题: ,object>

if(((IDictionary<string, object>)response.@object).ContainsKey("property_14"))
{
    // You've already addressed the issue, because you won't get a 
    // run-time exception since you'll access such property if it's already
    // in the returned response...
    object property_14 = response.@object.property_14;
}