如何在C#中反序列化JSON数组(或列表)?代码实现疑问
正确反序列化嵌套复杂JSON数组为C#列表的方案
首先得指出你原来代码里的几个问题:
- JSON字符串的变量声明语法错误(缺少
string类型); - 直接尝试把整个JSON反序列化成
List<Cookie>是行不通的——你的JSON结构嵌套非常深,最外层是包含head的对象,Rows数组里混合了字符串和多层嵌套数组,完全和List<Cookie>的结构不匹配。
下面给你两种可行的实现方案,分别用目前最常用的两个JSON序列化库:
方案一:使用Newtonsoft.Json(Json.NET,推荐)
这个库对复杂JSON结构的支持更友好,处理动态类型和嵌套数组更方便。
步骤1:定义匹配JSON结构的实体类
// 最外层根对象 public class Root { public Head head { get; set; } } // Head对象,包含Rows数组(混合类型,所以用object[]) public class Head { public object[] Rows { get; set; } } // 匹配JSON里的键值对对象 public class CookieItem { [JsonProperty("@Key")] // 映射JSON里的@Key字段 public string Key { get; set; } [JsonProperty("@value")] // 映射JSON里的@value字段 public string Value { get; set; } } // 你最终需要的Cookie实体 public class Cookie { public string Domain { get; set; } public string CookieName { get; set; } public string Purpose { get; set; } public string Lifetime { get; set; } }
步骤2:实现反序列化逻辑
using Newtonsoft.Json; using Newtonsoft.Json.Linq; public static List<Cookie> DeserializeNames() { // 修正后的JSON字符串(补全变量类型声明) string jsonStream = "{ \"head\": { \"Rows\": [ \"test 1\", [ [ { \"@Key\": \"Domain\", \"@value\": \"LocalHost\" }, { \"@Key\": \"Cookie name(s)\", \"@value\": \"Google\" }, { \"@Key\": \"Purpose\", \"@value\": \"Test\" }, { \"@Key\": \"lifetime\", \"@value\": \"test\" } ] ] ] } }"; // 1. 先反序列化为根对象 var root = JsonConvert.DeserializeObject<Root>(jsonStream); // 2. 逐层提取嵌套的键值对数组 // Rows[1]是嵌套的数组,里面的[0]又是一层数组,包含我们需要的Cookie键值对 var cookieItems = ((JArray)((JArray)root.head.Rows[1])[0]).ToObject<List<CookieItem>>(); // 3. 将键值对转换为Cookie对象 var cookie = new Cookie(); foreach (var item in cookieItems) { switch (item.Key) { case "Domain": cookie.Domain = item.Value; break; case "Cookie name(s)": cookie.CookieName = item.Value; break; case "Purpose": cookie.Purpose = item.Value; break; case "lifetime": cookie.Lifetime = item.Value; break; } } // 如果后续有多个Cookie组,这里可以扩展逻辑,当前返回包含单个Cookie的列表 return new List<Cookie> { cookie }; }
方案二:使用.NET Framework原生的JavaScriptSerializer
如果你只能用原生的JavaScriptSerializer,可以这样实现(注意:这个库对复杂类型的支持有限,代码会更繁琐):
步骤1:定义实体类
using System.Web.Script.Serialization; // 最外层根对象 public class Root { public Head head { get; set; } } public class Head { public object[] Rows { get; set; } } // 因为JavaScriptSerializer会直接匹配属性名,所以用@转义C#的关键字/特殊命名 public class CookieItem { public string @Key { get; set; } public string @value { get; set; } } // 目标Cookie实体和方案一一致 public class Cookie { public string Domain { get; set; } public string CookieName { get; set; } public string Purpose { get; set; } public string Lifetime { get; set; } }
步骤2:实现反序列化逻辑
public static List<Cookie> DeserializeNames() { string jsonStream = "{ \"head\": { \"Rows\": [ \"test 1\", [ [ { \"@Key\": \"Domain\", \"@value\": \"LocalHost\" }, { \"@Key\": \"Cookie name(s)\", \"@value\": \"Google\" }, { \"@Key\": \"Purpose\", \"@value\": \"Test\" }, { \"@Key\": \"lifetime\", \"@value\": \"test\" } ] ] ] } }"; JavaScriptSerializer serializer = new JavaScriptSerializer(); // 先反序列化为动态对象 dynamic root = serializer.DeserializeObject(jsonStream); // 逐层访问嵌套数组 var rows = root["head"]["Rows"] as System.Collections.ArrayList; var innerArray = rows[1] as System.Collections.ArrayList; var cookieItemsArray = innerArray[0] as System.Collections.ArrayList; // 将数组转换为CookieItem列表 List<CookieItem> cookieItems = serializer.ConvertToType<List<CookieItem>>(cookieItemsArray); // 转换为目标Cookie对象 Cookie cookie = new Cookie(); foreach (var item in cookieItems) { switch (item.@Key) { case "Domain": cookie.Domain = item.@value; break; case "Cookie name(s)": cookie.CookieName = item.@value; break; case "Purpose": cookie.Purpose = item.@value; break; case "lifetime": cookie.Lifetime = item.@value; break; } } return new List<Cookie> { cookie }; }
关键说明
- 永远要让C#实体类的结构匹配JSON的层级,不能跳过嵌套直接反序列化为目标类型;
- 如果JSON里有混合类型的数组(比如同时包含字符串和数组),要用
object[]或者动态类型来承接; - 优先选择Newtonsoft.Json,它的功能更强大,处理复杂JSON的效率和灵活性都远高于原生的
JavaScriptSerializer。
内容的提问来源于stack exchange,提问作者Trilok Pathak




