C#读取JSON文件后无法使用foreach循环操作数据的问题
图书馆管理系统JSON反序列化类型转换问题解决
问题说明
开发的图书馆管理系统支持用户注册、图书添加、借阅及归还功能。首次运行自动创建database.json时功能正常,但再次运行读取已存在的文件后,无法通过foreach循环处理数据。执行foreach (User user in (List<User>)database["users"])时,报错:无法将类型为'Newtonsoft.Json.Linq.JArray'的对象转换为类型'System.Collections.Generic.List
相关代码片段:
namespace LibraryManagementSystem { public class Library { public Dictionary<string, object> database; public Library() { database = new Dictionary<string, object> { { "books", new List<Book>() }, { "users", new List<User> { new User { Login = "admin", Password = "admin" } } }, { "registry", new List<Registry>() } }; Setup(); } private void Setup() { string cwd = Directory.GetCurrentDirectory(); string databasePath = Path.Combine(cwd, "database.json"); if (File.Exists(databasePath)) { string json = File.ReadAllText(databasePath); database = JsonConvert.DeserializeObject<Dictionary<string, object>>(json); Console.WriteLine("Library successfully loaded!"); Console.WriteLine(JsonConvert.SerializeObject(database)); } else if (!File.Exists(databasePath)) { Console.WriteLine("I can't find database.json file from last session..."); Console.WriteLine("No problem :) I will create new one!"); string json = JsonConvert.SerializeObject(database); File.WriteAllText(databasePath, json); Console.WriteLine(JsonConvert.SerializeObject(database)); } Console.WriteLine("Psst! I have hint for you :) there is list of avaliable users, please don't waste it!"); Console.WriteLine(JsonConvert.SerializeObject(database["users"])); } } }
生成的database.json内容:
{ "books":[], "users":[{"Login":"admin","Password":"admin"}], "registry":[] }
错误原因
使用JsonConvert.DeserializeObject<Dictionary<string, object>>()反序列化JSON时,JSON数组会被默认解析为JArray类型(Newtonsoft.Json的动态数组类型),而非预先定义的List<User>等强类型集合,直接强制转换会触发类型不匹配异常。
解决方案
方法1:反序列化为强类型模型(推荐)
创建与JSON结构匹配的强类型模型类,替代Dictionary<string, object>,反序列化时直接映射为强类型集合,避免类型转换问题。
步骤1:定义Database模型类
public class Database { public List<Book> books { get; set; } public List<User> users { get; set; } public List<Registry> registry { get; set; } }
步骤2:修改Library类代码
namespace LibraryManagementSystem { public class Library { public Database database; public Library() { database = new Database { books = new List<Book>(), users = new List<User> { new User { Login = "admin", Password = "admin" } }, registry = new List<Registry>() }; Setup(); } private void Setup() { string cwd = Directory.GetCurrentDirectory(); string databasePath = Path.Combine(cwd, "database.json"); if (File.Exists(databasePath)) { string json = File.ReadAllText(databasePath); // 反序列化为强类型Database对象 database = JsonConvert.DeserializeObject<Database>(json); Console.WriteLine("Library successfully loaded!"); Console.WriteLine(JsonConvert.SerializeObject(database)); } else { Console.WriteLine("I can't find database.json file from last session..."); Console.WriteLine("No problem :) I will create new one!"); string json = JsonConvert.SerializeObject(database); File.WriteAllText(databasePath, json); Console.WriteLine(JsonConvert.SerializeObject(database)); } Console.WriteLine("Psst! I have hint for you :) there is list of avaliable users, please don't waste it!"); Console.WriteLine(JsonConvert.SerializeObject(database.users)); } } }
修改后,直接使用foreach (User user in database.users)即可正常遍历用户集合。
方法2:手动将JArray转换为强类型集合
若需保留Dictionary<string, object>,可在读取JSON后手动将JArray转换为对应强类型集合,或在遍历前进行转换。
方式A:读取时转换
private void Setup() { string cwd = Directory.GetCurrentDirectory(); string databasePath = Path.Combine(cwd, "database.json"); if (File.Exists(databasePath)) { string json = File.ReadAllText(databasePath); var jObject = JObject.Parse(json); database = new Dictionary<string, object> { { "books", jObject["books"].ToObject<List<Book>>() }, { "users", jObject["users"].ToObject<List<User>>() }, { "registry", jObject["registry"].ToObject<List<Registry>>() } }; Console.WriteLine("Library successfully loaded!"); Console.WriteLine(JsonConvert.SerializeObject(database)); } // 其余代码不变 }
方式B:遍历时转换
// 在需要遍历users的位置添加转换逻辑 var users = ((JArray)database["users"]).ToObject<List<User>>(); foreach (User user in users) { // 执行用户相关处理逻辑 }
内容的提问来源于stack exchange,提问作者MichalK
相关产品推荐
相关产品推荐

