C# 使用JsonConverter JSON.net将JSON反序列化到对象列表

C# 使用JsonConverter JSON.net将JSON反序列化到对象列表,c#,json.net,C#,Json.net,我想将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 } ... ] } public class Bo

我想将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 }
            ...
    ]
}
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();
    }
}
我只想获取
结果
节点中的对象列表,因为有一些属性我想自己对其进行反序列化,所以我使用来自的实现来实现
JsonConverter
,他创建了名为
JsonCreationConverter
的派生泛型类
JsonCreationConverter
,该类具有protect abstract
Create
方法,该方法实际上反序列化了JSON,而JSON又被
JsonConverter
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;
    }
}
公共类BoringTypeConverter:JsonCreationConverter
{
受保护的覆盖列表创建(类型objectType,JObject JObject)
{
列表类型=新列表();
JArray结果=(JArray)jObject[“结果”];
//反序列化逻辑
...
返回钻孔类型;
}
}
我就是这样用的

JsonConvert.DeserializeObject<List<BoringType>>(jsonString, new BoringTypeConverter());
JsonConvert.DeserializeObject(jsonString,new BoringTypeConverter());
当我调试测试时,我发现
Create
方法成功地将JSON反序列化为
List
,但我一点击
serializer.Populate(jObjectReader,target)
就出现了错误
无法将JSON对象填充到类型“System.Collections.Generic.List1[BoringType]”。路径“元数据”,第2行,位置15。

所以我想知道这就是问题所在?

Create
方法没有对
metadata
字段执行任何操作,那么为什么它会抱怨
元数据

我创建了一个简单的示例,说明如何执行此操作:

  • 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;
        }
    }
    
    公共静态类JsonBase,其中T:BaseData
    {
    公共静态列表ReturnResultsList(字符串json)
    {
    var returnData=JsonConvert.DeserializeObject(json);
    返回数据。返回结果;
    }
    公共静态字符串返回元数据(字符串json)
    {
    var returnData=JsonConvert.DeserializeObject(json);
    返回returnData.metadata;
    }
    }
    
  • BaseData是一个类,它可能包含不同类型的数据,因为它是泛型的,并且包含与JSON相同的属性

    public class BaseData<T> where T: class 
    {
        public string metadata { get; set; }
        public List<T> results { get; set; }
    }
    
    公共类基本数据,其中T:class
    {
    公共字符串元数据{get;set;}
    公共列表结果{get;set;}
    }
    
  • 你想要的东西是你真正想要的东西

    public class SomeObjectTHatUwant:BaseData<SomeObjectTHatUwant>
    {
        public string category { get; set; }/// property for my case
        public string quantity { get; set; }
    
    }
    
    公共类SomeObjectTHatUwant:BaseData
    {
    我的案例的公共字符串类别{get;set;}///属性
    公共字符串数量{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;
            }
        }
    }
    
    stringurl=”http://readabook.16mb.com/api/allcategory";///此链接返回一个json
    列表响应=新列表()///你想要的数据
    专用异步任务LoadDataAsync(字符串uri)
    {
    字符串响应JSONSTRING=null;
    使用(var httpClient=new WebClient())
    {
    尝试
    {
    responseJsonString=httpClient.DownloadString(uri);
    Response=JsonBase.ReturnResultsList(responseJsonString);
    }
    捕获(例外)
    {
    投掷;
    }
    }
    }
    
  • 调用
    LoadDataAsync(url)此方法在案例响应字段中初始化,
    这是我们想要的一些对象的列表

  • (另外,对于LoadedDataAsync方法,我使用库System.Net.Http和System.Threading.Tasks) 代码示例:


    希望这有帮助。

    正如@dbc指出的那样,这个问题实际上是关于如何告诉
    JsonConvert.DeserializeObject
    它应该反序列化到哪种类型的对象

    所以,我实际做的是反序列化对象,然后我告诉
    JsonConvert
    将JSON放入我的
    BoringType
    字段中,该字段不包含
    元数据。这就是为什么我得到了一个错误,说它不能将JSON放入没有相应字段的类中

    事实证明,编写定制JsonConverter非常简单(一旦您了解了Linq的JSON)。
    我的转换器看起来像这样

    {
        "metadata":{ I don't care about metadata },
        "results": [
            { object that I really want },
            { object that I really want },
            { object that I really want }
                ...
        ]
    }
    
    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();
        }
    }
    
    公共类BoringTypeConverter:JsonConverter
    {
    public override bool CanRead=>true;
    public override List ReadJson(JsonReader读取器、类型objectType、列表existingValue、bool hasExistingValue、JsonSerializer序列化程序)
    {
    if(reader.TokenType==JsonToken.Null)
    返回null;
    列表类型=新列表();
    var jObject=jObject.Load(读卡器);
    JArray结果=(JArray)jObject[“结果”];
    foreach(结果中的var bor)
    {
    var钻孔=新钻孔类型();
    变量区域=(字符串)bor[“区域”];
    var source=(字符串)bor[“source”];
    JToken source=(字符串)bor[“source”];
    JToken target=(字符串)bor[“target”];
    区域=区域;
    无聊。来源=来源;
    Source=(字符串)Source[“id”];
    目标=(字符串)目标[“id”];
    钻孔类型。添加(钻孔);
    }
    返回钻孔类型;
    }
    公共重写void WriteJson(JsonWriter编写器、列表值、JsonSerializer序列化器)
    {
    抛出新的NotImplementedException();
    }
    }
    
    您的数据模型实际上是多态的吗?描述如何反序列化多态对象列表中的项。这在这里适用吗?你能提供一份吗?@dbc不,不是。谢谢你指出我,我没有仔细阅读这个问题,所以我认为答案是关于如何使用JsonConverter的,现在我明白我在做什么了。下次我将尝试改进这个有问题的例子。我认为它可以更优雅。谢谢你们的回答,我认为这是一个反序列化JSON的好方法,JSON以相同的模式出现(元数据、结果)。然而,事实并非如此