另一种方法,使用一个类对象,该对象定义具有公共前缀的每组属性为Dictionary<string, TValue>。
使用自定义 JsonConverter 将 JSON 反序列化,该自定义 JsonConverter 使用 Dictionary<string, string> 将 JSON 中的每组属性映射到类的属性:
Dictionary<string, string> map = new Dictionary<string, string>() {
["Descriptions"] = "descriptions_",
["OfficialTitles"] = "official_title_",
["AuthTowns"] = "auth_town_"
};
JSON 中映射到类中某个 Property 的所有属性都添加到相应的 Dictionary 中,并将值转换为类属性定义的 Type。
注意:您需要使映射器和类属性适应 JSON。您可以使用一些逻辑来确定 JSON 中的属性名称何时属于同一 组 并生成一个新的Dictionary<string, TValue> 以添加到类中,从而使该过程更加通用反射。
或者,如果您发现其他组,只需将更多属性添加到类离线。
将其称为:
(可能给班级起一个不那么愚蠢的名字:)
var result = new SimpleSequences().Deserialize(json);
助手类对象:
private class SimpleSequences
{
public SimpleSequences() {
Descriptions = new Dictionary<string, long[]>();
OfficialTitles = new Dictionary<string, string>();
AuthTowns = new Dictionary<string, string>();
}
public List<SimpleSequences> Deserialize(string json)
{
var options = new JsonSerializerSettings() {
Converters = new[] { new SimpleSequencesConverter() }
};
return JsonConvert.DeserializeObject<List<SimpleSequences>>(json, options);
}
public int Id { get; set; }
public Dictionary<string, long[]> Descriptions { get; set; }
public Dictionary<string, string> OfficialTitles { get; set; }
public Dictionary<string, string> AuthTowns { get; set; }
}
自定义 JsonConverter:
此转换器处理单个对象或对象数组(如您的问题所示),但始终返回 List<SimpleSequences>(可能包含单个对象)。根据需要修改。
public class SimpleSequencesConverter : JsonConverter
{
public override bool CanConvert(Type objectType) => true;
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType != JsonToken.StartArray && reader.TokenType != JsonToken.StartObject) {
throw new Exception($"Unexpected Type. Expecting Array or Object, got {reader.TokenType}");
}
var elementsList = new List<SimpleSequences>();
if (reader.TokenType == JsonToken.StartObject) {
elementsList.Add(GetPropertyValues(JObject.Load(reader)));
}
else {
while (reader.Read() && reader.TokenType != JsonToken.EndArray) {
elementsList.Add(GetPropertyValues(JObject.Load(reader)));
}
}
return elementsList;
}
private SimpleSequences GetPropertyValues(JToken token)
{
var element = new SimpleSequences();
element.Id = token["id"].ToObject<int>();
var descriptions = token.Children().Where(t => t.Path.StartsWith(map["Descriptions"]));
foreach (JProperty p in descriptions) {
element.Descriptions.Add(p.Path, p.Value.ToObject<long[]>());
}
var titles = token.Children().Where(t => t.Path.StartsWith(map["OfficialTitles"]));
foreach (JProperty p in titles) {
element.OfficialTitles.Add(p.Path, p.Value.ToString());
}
var authTowns = token.OfType<JToken>().Where(t => t.Path.StartsWith(map["AuthTowns"]));
foreach (JProperty p in authTowns) {
element.AuthTowns.Add(p.Path, p.Value.ToString());
}
return element;
}
public override bool CanWrite => false;
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
=> throw new NotImplementedException();
Dictionary<string, string> map = new Dictionary<string, string>() {
["Descriptions"] = "descriptions_",
["OfficialTitles"] = "official_title_",
["AuthTowns"] = "auth_town_"
};
}