在C#中使用System.Text.Json反序列化JSON至字典的问题
问题分析与解决方案
核心问题总结
你的代码无法成功反序列化的原因有以下几点:
- JSON结构外层包含
FullSchedule属性,并非直接对应字典对象,直接反序列化为Dictionary会匹配失败 System.Text.Json默认不支持反序列化为Stack<T>类型(仅原生支持列表、数组等常见集合)- 文件存在性判断逻辑错误(用
Directory.Exists检查文件路径,而非File.Exists) - 反序列化类型与返回类型不匹配(
Stack<Training?>vsStack<Training>)
步骤1:定义必要的基础类型
确保你的枚举Dag和类Training与JSON字段完全匹配:
public enum Dag { Maandag, Dinsdag, Woensdag, Donderdag, Vrijdag, Zaterdag, Zondag } public class Training { public string Name { get; set; } public string Description { get; set; } public int Trainingsort { get; set; } public int Hours { get; set; } public int Minutes { get; set; } }
步骤2:自定义Stack转换器
由于System.Text.Json不原生支持Stack<T>,需要实现自定义转换器:
public class StackConverter<T> : JsonConverter<Stack<T>> { public override Stack<T> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { // 先反序列化为List,再转换为Stack var list = JsonSerializer.Deserialize<List<T>>(ref reader, options); return list != null ? new Stack<T>(list) : new Stack<T>(); } public override void Write(Utf8JsonWriter writer, Stack<T> value, JsonSerializerOptions options) { // 序列化时将Stack转为List输出 JsonSerializer.Serialize(writer, value.ToList(), options); } }
步骤3:修正反序列化方法
以下是完整的修正代码,包含JSON结构匹配、转换器配置和错误处理优化:
public static Dictionary<Dag, Stack<Training>> ReadJSON(string path) { string jsonFilePath = $@"{path}.json"; // 修正文件存在性判断逻辑 if (!File.Exists(jsonFilePath)) throw new ArgumentException($"指定的JSON文件不存在:{jsonFilePath}"); string scheduleJson; try { // 简化文件读取逻辑 scheduleJson = File.ReadAllText(jsonFilePath); } catch (Exception ex) { throw new Exception($"读取文件失败:{ex.Message}", ex); } var serializerOptions = new JsonSerializerOptions { // 添加Stack转换器 Converters = { new StackConverter<Training>() }, // 允许枚举与JSON键大小写不匹配(可选,根据你的枚举定义调整) PropertyNameCaseInsensitive = true }; // 先解析外层的FullSchedule容器 var scheduleWrapper = JsonSerializer.Deserialize<ScheduleWrapper>(scheduleJson, serializerOptions); return scheduleWrapper?.FullSchedule ?? new Dictionary<Dag, Stack<Training>>(); } // 匹配JSON外层结构的包装类 public class ScheduleWrapper { public Dictionary<Dag, Stack<Training>> FullSchedule { get; set; } }
可选方案:不使用包装类
如果不想定义ScheduleWrapper,可以直接用JsonDocument提取FullSchedule节点:
public static Dictionary<Dag, Stack<Training>> ReadJSON(string path) { string jsonFilePath = $@"{path}.json"; if (!File.Exists(jsonFilePath)) throw new ArgumentException($"指定的JSON文件不存在:{jsonFilePath}"); string scheduleJson; try { scheduleJson = File.ReadAllText(jsonFilePath); } catch (Exception ex) { throw new Exception($"读取文件失败:{ex.Message}", ex); } var serializerOptions = new JsonSerializerOptions { Converters = { new StackConverter<Training>() }, PropertyNameCaseInsensitive = true }; using var jsonDoc = JsonDocument.Parse(scheduleJson); var fullScheduleElement = jsonDoc.RootElement.GetProperty("FullSchedule"); return JsonSerializer.Deserialize<Dictionary<Dag, Stack<Training>>>(fullScheduleElement.GetRawText(), serializerOptions); }
内容的提问来源于stack exchange,提问作者Loran Maes
相关产品推荐
相关产品推荐

