当前位置: 首页 > 面试题库 >

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

刘运浩
2023-03-14
问题内容

我有一个带有JSON数组的有效JSON对象。JSON数组没有花括号,并且包含逗号分隔的混合类型列表。看起来像这样:

{
    "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结构的类,为复杂数组提供了一个List:

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<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文件中,我正在反序列化如下:

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

当我运行该程序时,子对象(Rows)始终为null。我究竟做错了什么?


问题答案:

Json.Net没有将数组自动映射到类的功能。为此,您需要一个自定义JsonConverter。这是一个应该为您工作的通用转换器。它使用一个自定义[JsonArrayIndex]属性来标识类中的哪些属性与数组中的哪些索引相对应。如果JSON更改,这将使您轻松更新模型。另外,您可以安全地忽略类中不需要的属性,例如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班级,如下所示:

[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

注意:我没有实现WriteJson,因此,如果您将模型序列化回JSON,它将不会序列化回数组格式。相反,它将使用默认的对象序列化。



 类似资料:
  • 问题内容: 我的JSON有点弱,所以我需要一些帮助。 我正在尝试反序列化用户的JSON: 放入我用属性装饰的对象中: 我得到以下异常: Newtonsoft.Json.JsonSerializationException:在JSON中找不到必需的属性’user_id’。 这是因为JSON对象是一个数组吗?如果是这样,如何将其反序列化为一个User对象? 提前致谢! 问题答案: 正如Alexandr

  • 问题内容: 我正在尝试将json数据反序列化为模型类,但是失败了。这是我的工作: 这是我的模型的样子: 您可以看到我到达这里的Json:http : //api.worldbank.org/incomeLevels/LIC/countries? format=json 这是我得到的错误: 无法将JSON数组反序列化为“ Mvc4AsyncSample.Models.CountryModel”类型。

  • 问题内容: 我有一个JSON数组,其中包含具有不同属性的不同类型的对象。属性之一称为“类型”,它确定数组项的类型。这是我的数据示例: 为了将这些对象映射到我的.Net实现中,我定义了一组类:一个基类和几个子类(具有复杂的层次结构,具有4个“世代”)。这只是这些类的一个小示例: 我想达到的目的是能够将此数组反序列化为协变通用列表,声明为: 此列表应包含从TExpression继承的适当子类的实例,因

  • 问题内容: 我正在尝试将一些JSON数据反序列化为应用程序的对象。到现在为止还不错,因为JSON数据上的属性是静态的(带有值的键)。现在,我得到了一个结果,其中的关键是动态数据。 这是一个示例JSON网址: http://en.wikipedia.org/w/api.php?action=query&format=json&pageids=6695&prop=info 由此产生的JSON是: 好的

  • 问题内容: 我有由第三方编码为固定长度数组的json’ed 元组数组: 我想使用json魔术来获取的实例列表 请帮助我放置适当的注释,以使ObjectMapper发挥作用。 我无法控制传入的格式,而我所有的google’n都以答案来回答如何将适当的json对象(而非数组)数组映射到对象列表 问题答案: 添加以下注释: 并且它应该根据需要序列化条目。 另外:然后使用它来强制执行特定顺序是最安全的,因

  • 我在使用spring反序列化json数组时遇到一个问题。我有来自服务的json响应: 我使用spring WebFlux的新WebClient获得了这个json,代码如下: AccountorDerList AccountOrder是一个映射字段的简单pojo。 实际上,当我点击get时,它说: 如何使用新的webflux模块正确反序列化json?我做错了什么? 更新05/02/2018 两个答案