如何使用json.NET反序列化动态命名的根节点

这是json文件的一个示例:

{    "John Smith": {       "id": "72389",       "email": "johnsmith@gmail.com",       "books": [          {             "id": "0",             "title": "The Hunger Games",             "rating": "5"          },          {             "id": "1",             "title": "Harry Potter and the Order of the Phoenix",             "rating": "3"          },       ],       "magazines": [          {             "id": "2",             "title": "National Geographic",             "rating": "1"          },          {             "id": "3",             "title": "Wired",             "rating": "4"          }       ],    } } 

请注意,根节点有一个动态名称(John Smith),我需要反序列化的每个json都有不同的名称。 这个json结构需要按如下方式设置类:

 public class RootObject { public JohnSmith { get; set; } } public class JohnSmith //oops { public string id { get; set; } public string email { get; set; } public List books { get; set; } public List magazines { get; set; } } public class Book { public string id { get; set; } public string title { get; set; } public string rating { get; set; } } public class Magazine { public string id { get; set; } public string title { get; set; } public string rating { get; set; } } 

我的目标是反序列化“绕过/忽略”根对象,最重要的是动态命名节点 。 这并不重要,但我希望能够获取姓氏并将其设置为Person类的属性。

 public class Person { public string id { get; set; } public string email { get; set; } public string name { get; set; } public List books { get; set; } public List magazines { get; set; } } public class Book { public string id { get; set; } public string title { get; set; } public string rating { get; set; } } public class Magazine { public string id { get; set; } public string title { get; set; } public string rating { get; set; } } 

我现在就是这样做的:

 var jo = JObject.Parse(json); var deserializable = jo.First.First.ToString(); string name; var jp = (JProperty)jo.First; if (jp != null) name = jp.Name; var person = JsonConvert.DeserializeObject(deserializable); person.name = name; 

这工作正常,但我想知道,也许通过使用自定义JsonConverter可以做得更好? 我担心这有点过头了,所以我在这里要求一些帮助……

无论如何,如果有更好的方法来实现这一目标,请分享。

我会保留你的解决方案的第一部分(反序列化到JObject ),但我不会做另一个序列化。 我的代码看起来像这样:

 var jo = JObject.Parse(json); var jp = jo.Properties().First(); var name = jp.Name; var person = jp.Value.ToObject(); 

编辑:

如果您需要自定义转换器,可以使用以下代码。 转换器将您的对象转换为Person的列表,其中每个属性代表另一个Person

 class PersonListConverter : JsonConverter { public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { var list = (PersonList) value; writer.WriteStartObject(); foreach (var p in list.Persons) { writer.WritePropertyName(p.Name); serializer.Serialize(writer, p); } writer.WriteEndObject(); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var jo = serializer.Deserialize(reader); var result = new PersonList(); result.Persons = new List(); foreach (var prop in jo.Properties()) { var p = prop.Value.ToObject(); // set name from property name p.Name = prop.Name; result.Persons.Add(p); } return result; } public override bool CanConvert(Type objectType) { return objectType == typeof(PersonList); } } 

PersonList看起来像这样:

 [JsonConverter(typeof(PersonListConverter))] class PersonList { public List Persons { get; set; } } 

我首先尝试在原始JSON上使用正则表达式,提取名称,正则表达式用固定节点名称替换它,然后使用您现在知道的根节点调用反序列化修改后的结果。