C#类内嵌套对象序列化为JSON仅输出{}的问题排查与解决
问题分析与解决方案
核心原因
你遇到的appSession被序列化为{}的问题,本质是System.Text.Json的序列化规则限制:
- 默认仅序列化公共属性(带
get/set的成员),不序列化字段(无论公共还是私有); internal修饰的类/成员默认无法被序列化;- 反序列化时需要目标类有无参构造函数,否则无法实例化对象。
对照你的代码:
appSession中的LinkedSite是公共字段,IUSession是internal字段;ImageUploaderData的workAreaImages是私有字段;WorkingImage的EXIF_filename是私有字段;appSession只有带参数的构造函数,无默认无参构造。
这些都导致序列化器无法读取/写入对象的实际数据,最终输出空对象{}。
分步修复
1. 将字段改为公共属性
把所有需要序列化的字段改成带get/set的公共属性,这是最规范的做法:
修改appSession类:
public class appSession { // 公共属性替代公共字段 public SiteConnection LinkedSite { get; set; } // 若需序列化IUSession,改为public(或后续通过配置选项兼容internal) public ImageUploaderData IUSession { get; set; } // 添加无参构造函数,用于反序列化 public appSession() { } public appSession(SiteConnection linkedSite) { LinkedSite = new SiteConnection(linkedSite); IUSession = new ImageUploaderData(); } }
修改ImageUploaderData类:
// 若需序列化,建议改为public,或保留internal并配置序列化选项 public class ImageUploaderData { // 公共属性替代私有字段 public List<WorkingImage> WorkAreaImages { get; set; } public ImageUploaderData() { WorkAreaImages = new List<WorkingImage>(); } }
修改WorkingImage类:
public class WorkingImage : WorkingFile { public enum TaggingState { Untagged, Issue, Tagged } // 公共属性替代私有字段 public string EXIF_Filename { get; set; } // 保留构造函数,确保反序列化可用 public WorkingImage() : base() { selected = false; } public WorkingImage(string path) : base(path) { selected = false; } }
2. 配置序列化选项(可选,若需保留internal成员)
如果不想修改类的可见性(比如保留internal类),可以在序列化时配置JsonSerializerOptions,指定包含字段并允许访问非公共成员:
在UserData的Save、Create方法中修改选项:
var options = new JsonSerializerOptions { WriteIndented = true, // 包含所有字段(公共/私有/internal) IncludeFields = true, // 允许反序列化时访问非公共构造函数 ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor };
3. 优化序列化逻辑(更优实现)
把序列化/反序列化逻辑从UserData中抽离,做成独立工具类,降低耦合性,同时统一配置选项:
public static class JsonStorageHelper { private static readonly JsonSerializerOptions _defaultOptions = new() { WriteIndented = true, IncludeFields = true, // 根据需求选择是否启用 ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor }; public static async Task SaveToFileAsync<T>(T data, string filePath) { var folder = ApplicationData.Current.LocalFolder; var file = await folder.CreateFileAsync(filePath, CreationCollisionOption.ReplaceExisting); var json = JsonSerializer.Serialize(data, _defaultOptions); await FileIO.WriteTextAsync(file, json); } public static async Task<T?> LoadFromFileAsync<T>(string filePath) { var folder = ApplicationData.Current.LocalFolder; try { var file = await folder.GetFileAsync(filePath); var json = await FileIO.ReadTextAsync(file); return JsonSerializer.Deserialize<T>(json, _defaultOptions); } catch (FileNotFoundException) { return default; } } }
简化后的UserData类:
public class UserData { public List<appSession> userSessions { get; set; } public DatabaseConnection lastDatabaseConnection { get; set; } public string temp { get; set; } public UserData() { userSessions = new List<appSession>(); } public async Task SaveAsync() { await JsonStorageHelper.SaveToFileAsync(this, @"UserData\user.json"); } public static async Task<UserData> LoadOrCreateAsync() { var data = await JsonStorageHelper.LoadFromFileAsync<UserData>(@"UserData\user.json"); if (data == null) { data = new UserData(); await data.SaveAsync(); } return data; } }
验证修改
修复后,user.json应该能正确输出appSession的内容,示例如下:
{ "userSessions": [ { "LinkedSite": { /* SiteConnection的具体内容 */ }, "IUSession": { "WorkAreaImages": [] } } ], "lastDatabaseConnection": null, "temp": "test test test" }
内容的提问来源于stack exchange,提问作者Mark L
相关产品推荐
相关产品推荐

