将JSON搜索结果反序列化为强类型列表(JSON.NET)

时间:2015-02-21 14:29:25

标签: c# json json.net deserialization

我有JSON的搜索结果,我想将其反序列化为强类型对象

例如:

{
    searchresult: {
        resultscount: 15,
        results: [
            {
                resultnumber: 1,
                values: [
                    {
                        key:    "bookid",
                        value:  1424
                    },
                    {
                        key:    "name",
                        value:  "C# in depth"
                    },
                ]
            }
        ]
    }
}

我有这个POCO

public class Book {
    public int BookId { get; set; }
    public string Name { get; set; }
}

我想获得一本书清单。是的,我可以为这种情况编写自己的自定义反序列化器,但我想使用默认的反序列化器。

是否可以做类似的事情?

IEnumerable<Book> books = JsonConvert.DeserializeObject<IEnumerable<Book>>(json);

1 个答案:

答案 0 :(得分:2)

Json.NET不会在没有任何自定义的情况下执行此操作。您有以下方法:

  1. 将您的课程发布到http://json2csharp.com/以创建JSON的文字表示,然后使用Linq将结果转换为Book类列表:

    public class Value
    {
        public string key { get; set; }
        public string value { get; set; } // Type changed from "object" to "string".
    }
    
    public class Result
    {
        public int resultnumber { get; set; }
        public List<Value> values { get; set; }
    }
    
    public class Searchresult
    {
        public int resultscount { get; set; }
        public List<Result> results { get; set; }
    }
    
    public class RootObject
    {
        public Searchresult searchresult { get; set; }
    }
    

    然后

        var root = JsonConvert.DeserializeObject<RootObject>(json);
        var books = root.searchresult.results.Select(result => new Book { Name = result.values.Find(v => v.key == "name").value, BookId = result.values.Find(v => v.key == "bookid").value });
    
  2. 创建自定义JsonConverter,以便在读取时将JSON转换为您的POCO,例如:

    internal class BookConverter : JsonConverter
    {
        public override bool CanWrite
        {
            get
            {
                return false;
            }
        }
    
        public override bool CanConvert(Type objectType)
        {
            return objectType == typeof(Book);
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            var values = serializer.Deserialize<List<KeyValuePair<string, string>>>(reader);
            if (values == null)
                return existingValue;
            var book = existingValue as Book;
            if (book == null)
                book = new Book();
            // The following throws an exception on missing keys.  You could handle this differently if you prefer.
            book.BookId = values.Find(v => v.Key == "bookid").Value;
            book.Name = values.Find(v => v.Key == "name").Value;
            return book;
        }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
    }
    
    public class Result
    {
        public int resultnumber { get; set; }
    
        [JsonProperty("values")] 
        [JsonConverter(typeof(BookConverter))]
        public Book Book { get; set; }
    }
    
    public class Searchresult
    {
        public int resultscount { get; set; }
        public List<Result> results { get; set; }
    }
    
    public class RootObject
    {
        public Searchresult searchresult { get; set; }
    }
    

    然后

        var root = JsonConvert.DeserializeObject<RootObject>(json);
        var books = root.searchresult.results.Select(result => result.Book);
    

    这里我只实现了ReadJson,因为您的问题仅询问反序列化。如果需要,您可以类似地实施WriteJson

  3. 使用Linq to JSON将JSON加载到JObject的结构化层次结构中,然后使用Linq将结果转换为Book&lt; < / p>

        var books = 
            JObject.Parse(json).Descendants()
                .OfType<JProperty>()
                .Where(p => p.Name == "values")
                .Select(p => p.Value.ToObject<List<KeyValuePair<string, string>>>())
                .Select(values => new Book { Name = values.Find(v => v.Key == "name").Value, BookId = values.Find(v => v.Key == "bookid").Value })
                .ToList();