我想反序列化JSON到对象列表,JSON具有这样的结构。
{
"metadata":{ I don't care about metadata },
"results": [
{ object that I really want },
{ object that I really want },
{ object that I really want }
...
]
}
我只想获取results
节点内的对象列表,并且由于我想自己反序列化某些属性,因此我使用Alain's answer in "How to implement custom JsonConverter in JSON.NET to deserialize a List of base class objects?"中的实现来实现JsonConverter
,他创建了JsonConverter
派生的名为JsonCreationConverter<T>
的泛型类,该类具有保护抽象的Create
方法,该方法实际上反序列化了JSON,而JSON又被JsonConverter
的{{1}}调用。
我的派生类的签名及其ReadJson
签名就像
Create
我像这样使用它
public class BoringTypeConverter: JsonCreationConverter<List<BoringType>>
{
protected override List<BoringType> Create(Type objectType, JObject jObject)
{
List<BoringType> boringTypes = new List<BoringType>();
JArray results = (JArray)jObject["results"];
// deserialize logic
...
return boringTypes;
}
}
在调试测试时,我发现JsonConvert.DeserializeObject<List<BoringType>>(jsonString, new BoringTypeConverter());
方法成功地将JSON反序列化为Create
,但是当我点击List<BoringType>
时,我得到了错误serializer.Populate(jObjectReader, target)
所以我想知道这是问题所在吗?
Cannot populate JSON object onto type 'System.Collections.Generic.List1[BoringType]'. Path 'metadata', line 2, position 15.
方法没有对Create
字段做任何事情,那么为什么它抱怨metadata
?
答案 0 :(得分:2)
我创建了一个简单的示例,您将如何做到这一点:
JsonBase是负责数据反序列化的类
public static class JsonBase<T> where T: BaseData<T>
{
public static List<T> ReturnResultsList(string json)
{
var returnData = JsonConvert.DeserializeObject<BaseData<T>>(json);
return returnData.results;
}
public static string ReturnMetaData(string json)
{
var returnData = JsonConvert.DeserializeObject<BaseData<T>>(json);
return returnData.metadata;
}
}
BaseData是类,因为它是通用的,所以可能包含不同类型的数据,并且它包含与JSON相同的属性
public class BaseData<T> where T: class
{
public string metadata { get; set; }
public List<T> results { get; set; }
}
SomeObjectTHatUwant是您真正想要的对象
public class SomeObjectTHatUwant:BaseData<SomeObjectTHatUwant>
{
public string category { get; set; }/// property for my case
public string quantity { get; set; }
}
在您的存储库或某个类中,放入以下方法和字段:
string url = "http://readabook.16mb.com/api/allcategory";///this link return an json
List<SomeObjectTHatUwant> Response = new List<SomeObjectTHatUwant>();///the data you want
private async Task LoadDataAsync(string uri)
{
string responseJsonString = null;
using (var httpClient = new WebClient())
{
try
{
responseJsonString = httpClient.DownloadString(uri);
Response = JsonBase<SomeObjectTHatUwant>.ReturnResultsList(responseJsonString);
}
catch (Exception)
{
throw;
}
}
}
调用LoadDataAsync(url);
,此方法在我们的案例Respone字段中初始化,
这是SomeObjectTHatUwant的列表。
(PS。对于方法LoadedDataAsync,我使用库System.Net.Http和System.Threading.Tasks) 代码示例:https://github.com/IonCojucovschi/JsonDeserializeGenericForm
希望获得帮助。
答案 1 :(得分:1)
正如@dbc向我指出的那样,问题How to implement custom JsonConverter in JSON.NET to deserialize a List of base class objects?实际上是关于如何告诉JsonConvert.DeserializeObject
应该反序列化为哪种类型的对象。
所以,我实际上是在对对象进行反序列化,然后告诉JsonConvert
将JSON放入我的BoringType
,其中不包含metadata
字段。因此,为什么我得到错误的字面意思是它无法将JSON放入没有相应字段的类中。
事实证明,编写自定义JsonConverter非常简单(一旦您知道LINQ的JSON)。
我的转换器看起来像这样。
public class BoringTypeConverter : JsonConverter<List<BoringType>>
{
public override bool CanRead => true;
public override List<BoringType> ReadJson(JsonReader reader, Type objectType, List<BoringType> existingValue, bool hasExistingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
List<BoringType> boringTypes = new List<BoringType>();
var jObject = JObject.Load(reader);
JArray results = (JArray)jObject["results"];
foreach (var bor in results)
{
var boring = new BoringType();
var region = (string)bor["region"];
var source = (string)bor["source"];
JToken source = (string)bor["source"];
JToken target = (string)bor["target"];
boring.Region = region;
boring.Source = source;
boring.Source = (string)source["id"];
boring.Target = (string)target["id"];
boringTypes.Add(boring);
}
return boringTypes;
}
public override void WriteJson(JsonWriter writer, List<BoringType> value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}