如何使用 Json.Net 将 JSON 数组反序列化为对象?

How to deserialize a JSON array into an object using Json.Net?(如何使用 Json.Net 将 JSON 数组反序列化为对象?)
本文介绍了如何使用 Json.Net 将 JSON 数组反序列化为对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

问题描述

我有一个有效的 JSON 对象,其中包含一个 JSON 数组.JSON 数组没有大括号,其中包含一个逗号分隔的混合类型列表.它看起来像这样:

I've a valid JSON object that has a JSON array in it. The JSON array doesn't have curly braces and contains a comma separated list of mixed type in it. It looks like this:

{
    "ID": 17,
    "Days": 979,
    "Start_Date": "10/13/2012",
    "End_Date": "11/12/2012",
    "State": "",
    "Page": 1,
    "Test": "Valid",
    "ROWS": [
        [441210, "A", "12/31/2009", "OK", "Done", "KELLEY and Co'", "12/31/2009", "06/29/2010", "TEXAS", "Lawyers", 6, "", "<img src="/includes/images/Icon_done.gif" border="0" alt="Done" title="Done" />"],
        [441151, "B", "12/31/2009", "No", "In-process", "Sage & Co", "12/31/2009", "06/29/2010", "CALIFORNIA", "Realtor", 6, "", "<img src="/includes/images/Icon_InProcess.gif" border="0" alt="In Process" title="In Process" />"]
    ]
}

我创建了一个类来反映 JSON 结构,其中包含一个复杂数组的列表:

I've created a class to reflect the JSON structure, having a List for the complex array:

class myModel
{
    public int ID { get; set; }
    public int Days { get; set; }
    public DateTime StartDate { get; set; }
    public DateTime EndDate { get; set; }
    public string State { get; set; }
    public string Page { get; set; }
    public string Test { get; set; }
    List<ChildModel> Rows { get; set; }
}

我也用 List of a List 对其进行了测试:

I've tested it with a List of a List too:

List<List<ChildModel>> Rows { get; set; }

还有这样的子模型:

class ChildModel
{
    public int ID { get; set; }
    public string StatusId { get; set; }
    public DateTime ContactDate { get; set; }
    public string State { get; set; }
    public string Status { get; set; }
    public string CustomerName { get; set; }
    public DateTime WorkStartDate { get; set; }
    public DateTime WorkEndDate { get; set; }
    public string Territory { get; set; }
    public string CustType { get; set; }
    public int JobOrder { get; set; }
    public string Filler { get; set; }
    public string Link { get; set; }
}

在我的 program.cs 文件中,我像这样反序列化它:

In my program.cs file, I'm deserializing it like this:

using (StreamReader r = new StreamReader(@"D:1.json"))
{
    myModel items = JsonConvert.DeserializeObject<myModel>(r.ReadToEnd());
}

当我运行这个程序时,子对象(行)总是null.我做错了什么?

When I run this program, the child object (Rows) is always null. What am I doing wrong?

推荐答案

Json.Net 没有自动将数组映射到类的功能.为此,您需要一个自定义的 JsonConverter.这是一个适合您的通用转换器.它使用自定义 [JsonArrayIndex] 属性来识别类中的哪些属性对应于数组中的哪些索引.如果 JSON 发生变化,这将允许您轻松更新模型.此外,您可以安全地从类中省略不需要的属性,例如 Filler.

Json.Net does not have a facility to automatically map an array into a class. To do so you need a custom JsonConverter. Here is a generic converter that should work for you. It uses a custom [JsonArrayIndex] attribute to identify which properties in the class correspond to which indexes in the array. This will allow you to easily update your model if the JSON changes. Also, you can safely omit properties from your class that you don't need, such as Filler.

代码如下:

public class JsonArrayIndexAttribute : Attribute
{
    public int Index { get; private set; }
    public JsonArrayIndexAttribute(int index)
    {
        Index = index;
    }
}

public class ArrayToObjectConverter<T> : JsonConverter where T : class, new()
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(T);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JArray array = JArray.Load(reader);

        var propsByIndex = typeof(T).GetProperties()
            .Where(p => p.CanRead && p.CanWrite && p.GetCustomAttribute<JsonArrayIndexAttribute>() != null)
            .ToDictionary(p => p.GetCustomAttribute<JsonArrayIndexAttribute>().Index);

        JObject obj = new JObject(array
            .Select((jt, i) =>
            {
                PropertyInfo prop;
                return propsByIndex.TryGetValue(i, out prop) ? new JProperty(prop.Name, jt) : null;
            })
            .Where(jp => jp != null)
        );

        T target = new T();
        serializer.Populate(obj.CreateReader(), target);

        return target;
    }

    public override bool CanWrite
    {
        get { return false; }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

要使用转换器,您需要标记您的 ChildModel 类,如下所示:

To use the converter, you need to mark up your ChildModel class as shown below:

[JsonConverter(typeof(ArrayToObjectConverter<ChildModel>))]
class ChildModel
{
    [JsonArrayIndex(0)]
    public int ID { get; set; }
    [JsonArrayIndex(1)]
    public string StatusId { get; set; }
    [JsonArrayIndex(2)]
    public DateTime ContactDate { get; set; }
    [JsonArrayIndex(3)]
    public string State { get; set; }
    [JsonArrayIndex(4)]
    public string Status { get; set; }
    [JsonArrayIndex(5)]
    public string CustomerName { get; set; }
    [JsonArrayIndex(6)]
    public DateTime WorkStartDate { get; set; }
    [JsonArrayIndex(7)]
    public DateTime WorkEndDate { get; set; }
    [JsonArrayIndex(8)]
    public string Territory { get; set; }
    [JsonArrayIndex(9)]
    public string CustType { get; set; }
    [JsonArrayIndex(10)]
    public int JobOrder { get; set; }
    [JsonArrayIndex(12)]
    public string Link { get; set; }
}

然后像往常一样反序列化,它应该可以按您的意愿工作.这是一个演示:https://dotnetfiddle.net/n3oE3L

Then just deserialize as usual and it should work as you wanted. Here is a demo: https://dotnetfiddle.net/n3oE3L

注意:我没有实现WriteJson,所以如果你把你的模型序列化回JSON,它不会序列化回数组格式;相反,它将使用默认的对象序列化.

Note: I did not implement WriteJson, so if you serialize your model back to JSON, it will not serialize back to the array format; instead it will use the default object serialization.

这篇关于如何使用 Json.Net 将 JSON 数组反序列化为对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

本站部分内容来源互联网,如果有图片或者内容侵犯了您的权益,请联系我们,我们会在确认后第一时间进行删除!

相关文档推荐

Force JsonConvert.SerializeXmlNode to serialize node value as an Integer or a Boolean(强制 JsonConvert.SerializeXmlNode 将节点值序列化为整数或布尔值)
Using JSON to Serialize/Deserialize TimeSpan(使用 JSON 序列化/反序列化 TimeSpan)
Could not determine JSON object type for type quot;Classquot;(无法确定类型“Class的 JSON 对象类型.)
How to deserialize a JSONP response (preferably with JsonTextReader and not a string)?(如何反序列化 JSONP 响应(最好使用 JsonTextReader 而不是字符串)?)
how to de-serialize JSON data in which Timestamp it-self contains fields?(如何反序列化时间戳本身包含字段的JSON数据?)
JSON.Net custom contract serialization and Collections(JSON.Net 自定义合约序列化和集合)