使用Json.Net反序列化Json对象

3

我正在尝试使用Json.net反序列化一个对象。我已经成功地完成了这个过程,但这更像是一种hack方法,因此我正在寻找更好/更合适的方法来完成。

{
"page":"admin",
"context":"id",
"records":{
            "rCount":6,
            "1":[
               {
                  "name":"Romeo",
                  "dob":"01\/01\/1970"
               },
               {
                  "name":"Harry",
                  "dob":"10\/10\/2012"
               },
               {
                  "name":"Lee",
                  "dob":"17\/10\/2012"
               }],
            "2":[
               {
                  "name":"Mark",
                  "dob":"01\/01\/1970"
               },
               {
                  "name":"Jack",
                  "dob":"10\/10\/2012"
               },
               {
                  "name":"Json",
                  "dob":"17\/10\/2012"
               }],

}}

这是一个JSON字符串,问题出在records对象上。如果它没有变量,那么它可以被反序列化为字典,但由于变量的存在,它无法正确地被反序列化为字典。应该如何正确地对这个对象进行反序列化呢?
以下是我的解决方法:
class Program
{
static void Main(string[] args)
{
    var recordFile = JsonConvert.DeserializeObject<RecordFile>(Properties.Resources.data);
}

public class RecordFile
{
    public string Page { get; set; }
    public string Context { get; set; }
    public Records Records { get; set; }
}

public class Records
{
    public int RCount { get; set; }
    [JsonExtensionData]
    private Dictionary<string, object> _reocordList;

    public List<Record[]> RecordList
    {
        get
        {
            if (_reocordList != null && _reocordList.Count > 0)
            {
                return _reocordList.Values.Select(record => JsonConvert.DeserializeObject<Record[]>(record.ToString())).ToList();
            }
            return new List<Record[]>();
        }
    }

}

public class Record
{
    public string Name { get; set; }
    public string Dob { get; set; }
}
}

@AndrewWhitaker 没有其他反序列化的方法。我使用 Dictionary<string, object> 是因为 JsonExtensionDataAttributeList<Record[]>Dictionary<string, Record[]> 都可以完成工作。 - Abdullah Saleem
是的,我发完评论后就意识到了,哈哈。 - Andrew Whitaker
3个回答

1
我假设您想要完全摆脱Records类,最终得到类似于这样的结果:
public class RecordFile
{
    public string Page { get; set; }
    public string Context { get; set; }
    public Dictionary<string, Record[]> Records { get; set; }
}

public class Record
{
    public string Name { get; set; }
    public string Dob { get; set; }
}

由于您完全不关心JSON中的records.rCount属性,因此您可以指定一个新的错误处理程序来简单地忽略该属性:

var recordFile = JsonConvert.DeserializeObject<RecordFile>(
    jsonString, 
    new JsonSerializerSettings 
    {
        Error = (sender, args) =>
        {
            if (args.ErrorContext.Path == "records.rCount")
            {
                // Ignore the error
                args.ErrorContext.Handled = true;
            }
        }
    });

现在,当遇到问题属性时,反序列化程序将直接跳过它。另一个选择是编写自定义转换器,但仅仅为了忽略一个属性而这样做感觉有些大材小用。
示例:https://dotnetfiddle.net/3svPqk

1
您可以使用 jObject 来手动解析 JSON:
public class RecordFile
{
    public string Page { get; set; }
    public string Context { get; set; }
    public Records Records { get; set; }
}

public class Records
{
    public int RCount { get; set; }
    public IDictionary<string, List<Record>> RecordsDictionary { get; set; } 
}


public class Record
{
    public string Name { get; set; }
    public string Dob { get; set; }
}

然后:

var jObject = JObject.Parse(\* your json *\);
var recordFile = new RecordFile
{
    Page = jObject.Value<string>("page"),
    Context = jObject.Value<string>("context"),
    Records = new Records
    {
        RCount = jObject["records"].Value<int>("rCount"),
        RecordsDictionary =
            jObject["records"].Children<JProperty>()
                              .Where(prop => prop.Name != "rCount")
                              .ToDictionary(prop => prop.Name),
                                            prop =>
                                            prop.Value.ToObject<List<Record>>())
    }

};

当属性不存在时,处理案例可能会很容易。

1
到目前为止,其他已发布的答案都应该有效。 为了完整起见,我将展示如何使用自定义的JsonConverter来解决这个问题,并且还可以简化您的模型。

以下是转换器的代码:

class RecordFileConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(RecordFile));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject jo = JObject.Load(reader);
        RecordFile rf = new RecordFile();
        rf.Page = (string)jo["page"];
        rf.Context = (string)jo["context"];
        JObject records = (JObject)jo["records"];
        rf.RecordCount = (int)records["rCount"];
        rf.Records = records.Properties()
                            .Where(p => p.Name != "rCount")
                            .Select(p => p.Value.ToObject<Record[]>())
                            .ToList();
        return rf;
    }

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

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

要使用转换器,请按照以下示例更改您的模型类。(请注意,RecordFile 类具有 JsonConverter 属性,用于将自定义的 RecordFileConverter 与其链接。还请注意,Records 类已被删除,而 RCountRecordList 属性已移至 RecordFile 类并重命名。)
[JsonConverter(typeof(RecordFileConverter))]
public class RecordFile
{
    public string Page { get; set; }
    public string Context { get; set; }
    public int RecordCount { get; set; }
    public List<Record[]> Records { get; set; }
}

public class Record
{
    public string Name { get; set; }
    public string Dob { get; set; }
}

然后,像平常一样反序列化:
var recordFile = JsonConvert.DeserializeObject<RecordFile>(json);

演示: https://dotnetfiddle.net/jz3zUT


非常感谢,那非常有帮助。 - Abdullah Saleem
没问题,很高兴能帮助到你。 - Brian Rogers

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接