我从REST请求中获取以下json有效负载。
{
"version": "1.1",
"date": "2017-01-06",
"count": "130",
"0": {
"artist": "Artist 1",
"title": "Title 1"
},
"1": {
"artist": "Artist 2",
"title": "Title 2"
},
...
"49": {
"artist": "Artist 50",
"title": "Title 50"
}
}
如您所见,有几个数字根元素。这些元素在响应中索引对象,因此我不需要数字本身,我只需要它们所代表的Song
对象。我还需要count
知道我是否需要拨打服务器来获取下一页歌曲(服务器每次调用最多返回50 Song
个对象。)
以下是Song
课程的内容:
public class Song
{
public string artist {get; set;}
public string title {get; set;}
}
但是我在获取根元素方面遇到了问题。我试图模仿有动态子元素时使用的过程,但这不起作用。
public class SongsResponse
{
public string version { get; set; }
public string date { get; set; }
public string count {get; set; }
public Dictionary<string, Song> songs { get; set; }
}
我已经看到过&#34;扔掉的解决方案&#34; version
,date
和count
以及没有预定义类的其他人。
但我需要count
,理想情况下我希望能够使用预定义的类。
答案 0 :(得分:1)
您不需要包含索引。歌曲的索引是因为它们将被反序列化为集合。像这样更改架构:
{
"version":"1.1",
"date":"2017-01-06",
"count":"130",
"songs":[
{
"artist":"Artist 1",
"title":"Title 1"
},
{
"artist":"Artist 2",
"title":"Title 2"
},
{
"artist":"Artist 3",
"title":"Title 3"
}
]
}
public class Song
{
public string artist {get; set;}
public string title {get; set;}
}
public class SongsResponse
{
public string version { get; set; }
public string date { get; set; }
public string count {get; set; }
public List<Song> songs { get; set; }
}
因此,您可能无法控制发送给您的json,但您仍然可以控制本地域对象以及如何反序列化json。我会坚持上面定义的类定义,并创建一个自定义JsonConverter
,您可以使用它将响应反序列化为更有意义的内容。实际上,当你在这里时,你可以让你的SongsResponse
课程变得更好。通过为date
和count
属性使用适当的类型(如果您不打算利用它,为什么要使用强类型语言)。
所以这堂课:
public class SongsResponseJsonConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException("Unnecessary because CanWrite is false. The type will skip the converter.");
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var result = new SongsResponse();
var obj = JObject.Load(reader);
result.version = obj["version"].Value<string>();
result.date = obj["date"].Value<DateTime>();
result.count = obj["count"].Value<int>();
result.songs =
obj
.Properties()
.Where(x => !(new string[] { "version", "date", "count" }.Contains(x.Name)))
.Select(x => new { Id = int.Parse(x.Name), Song = x })
.OrderBy(x => x.Id)
.Select(x => x.Song.Value.ToObject<Song>())
.ToList();
return result;
}
public override bool CanRead
{
get { return true; }
}
public override bool CanWrite
{
get { return false; }
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof(SongsResponse);
}
}
您可以这样使用:
var json = @"
{
""version"": ""1.1"",
""date"": ""2017-01-06"",
""count"": ""130"",
""0"": {
""artist"": ""Artist 1"",
""title"": ""Title 1""
},
""1"": {
""artist"": ""Artist 2"",
""title"": ""Title 2""
},
""49"": {
""artist"": ""Artist 50"",
""title"": ""Title 50""
}
}";
var response = JsonConvert.DeserializeObject<SongsResponse>(json, new SongsResponseJsonConverter());
答案 1 :(得分:0)
可以使用常用方法反序列化JSON的常量部分,然后使用JSON2LINQ构造动态部分。在您的特定情况下,它看起来如下:
var json = JObject.Parse(responseString);
var response = json.ToObject<SongsResponse>();
response.songs = json.Properties().Where(t => Regex.Match(t.Name, "\\d+").Success).ToDictionary(t => t.Name, t => t.Value.ToObject<Song>());
注意:在第一次调用后,Regex.Match会缓存regex对象,并且所有后续调用都会重用该对象。