如果您的键/值对不固定并且数据必须是可配置的,那么 Newtonsoft.json 有一个可以在这里使用的功能,那就是[JsonExtensionData]
阅读更多 http://james.newtonking.com/archive/2013/10/14/json-net-5-0-release-7-immutable-collections
现在,当对象被序列化时,就会写入扩展数据。读取和写入扩展数据可以自动往返所有 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>();
}
}
在上面的课程中,您知道Qaz
and Wsx
始终存在于您的 json 中,无论它们包含值还是 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();