C#自定义单例Settings类嵌套成员访问及层级分组实现咨询
自定义C#设置类的正确实现方案
核心问题解答
你要实现的单例+分组访问+序列化需求,嵌套类+实例化分组属性是完全合理的方案(并非唯一方式,但在分组语义上最清晰)。你之前的第二种写法方向正确,只需优化命名、完善初始化逻辑,同时处理好多层嵌套和动态表的场景即可。
基础实现:分组访问的标准写法
无需给嵌套类加下划线前缀,用清晰命名即可,同时在MQSettings构造函数中初始化所有分组对象,避免空引用:
internal class MQSettings : BaseClasses.SaveableObject { public override string Filepath => StaticSettings.MQSettingsPath; // 基础配置项,初始化默认空集合 internal List<string> MandatoryFolders { get; set; } = new(); internal List<string> MandatoryTables { get; set; } = new(); // 分组属性 internal Foldernames Foldernames { get; set; } internal Tablenames Tablenames { get; set; } // 构造函数:初始化分组对象+默认值 public MQSettings() { Foldernames = new Foldernames(); Tablenames = new Tablenames(); // 设置默认值 Foldernames.Config = "Configs"; Foldernames.Backups = "Backups"; Tablenames.User = "Users"; Tablenames.Members = "Members"; } // 分组嵌套类 internal class Foldernames { internal string Config { get; set; } internal string Backups { get; set; } // 更多路径配置 } internal class Tablenames { internal string Members { get; set; } internal string User { get; set; } // 更多表名配置 } }
这样就能按你想要的方式访问:
string configFolder = LoadedData.Settings.Foldernames.Config; string userTable = LoadedData.Settings.Tablenames.User;
多层嵌套的实现(如数据库字段)
对于Database.Fieldnames.UserTable.ID这类多层分组,直接延续嵌套类逻辑,确保每层对象都被初始化:
internal class MQSettings : BaseClasses.SaveableObject { public override string Filepath => StaticSettings.MQSettingsPath; internal Foldernames Foldernames { get; set; } internal DatabaseSettings Database { get; set; } public MQSettings() { Foldernames = new Foldernames(); Database = new DatabaseSettings(); // 初始化默认值 Database.Credentials = new AppName.DataTypes.Database.Credentials(); Database.Fieldnames.UserTable.ID = "user_id"; Database.Fieldnames.UserTable.Name = "user_name"; } internal class Foldernames { internal string Config { get; set; } internal string Templates { get; set; } internal string Backups { get; set; } } internal class DatabaseSettings { internal AppName.DataTypes.Database.Credentials? Credentials { get; set; } internal FieldNames Fieldnames { get; set; } public DatabaseSettings() { Fieldnames = new FieldNames(); } internal class FieldNames { internal UserTableFieldNames UserTable { get; set; } internal MemberTableFieldNames MemberTable { get; set; } public FieldNames() { UserTable = new UserTableFieldNames(); MemberTable = new MemberTableFieldNames(); } internal class UserTableFieldNames { internal string ID { get; set; } internal string Name { get; set; } } internal class MemberTableFieldNames { internal string ID { get; set; } internal string Email { get; set; } } } } }
访问方式:
string userIdColumn = LoadedData.Settings.Database.Fieldnames.UserTable.ID;
动态表的处理(支持新增表的字段配置)
如果要支持运行时创建的新表,不能用固定嵌套类,改用Dictionary<string, TableFieldConfig>存储动态表配置,同时保留固定表的嵌套类方便访问:
internal class MQSettings : BaseClasses.SaveableObject { public override string Filepath => StaticSettings.MQSettingsPath; internal DatabaseSettings Database { get; set; } public MQSettings() { Database = new DatabaseSettings(); // 初始化固定表默认值 Database.FixedFieldNames.UserTable.ID = "user_id"; // 初始化动态表字典 Database.DynamicTableFields = new Dictionary<string, TableFieldConfig>(); } internal class DatabaseSettings { internal FixedFieldNames FixedFieldNames { get; set; } // key为表名,存储动态表的字段配置 internal Dictionary<string, TableFieldConfig> DynamicTableFields { get; set; } public DatabaseSettings() { FixedFieldNames = new FixedFieldNames(); } internal class FixedFieldNames { internal UserTableFieldNames UserTable { get; set; } public FixedFieldNames() { UserTable = new UserTableFieldNames(); } internal class UserTableFieldNames { internal string ID { get; set; } internal string Name { get; set; } } } } // 通用表字段配置类 internal class TableFieldConfig { internal string ID { get; set; } internal string Name { get; set; } // 其他通用字段 } }
访问动态表字段:
// 获取已存在的动态表字段 if(LoadedData.Settings.Database.DynamicTableFields.TryGetValue("NewTable", out var fields)) { string newTableId = fields.ID; } // 添加新表配置 LoadedData.Settings.Database.DynamicTableFields["NewTable"] = new TableFieldConfig { ID = "new_table_id", Name = "new_table_name" };
序列化注意事项
因为类和属性都是internal,使用System.Text.Json时需添加[JsonInclude]或配置序列化器支持internal成员:
// System.Text.Json序列化示例 var options = new JsonSerializerOptions { WriteIndented = true, IncludeFields = true, PropertyNameCaseInsensitive = true, // 允许访问internal成员 Converters = { new JsonStringEnumConverter() } }; // 保存 File.WriteAllText(settings.Filepath, JsonSerializer.Serialize(settings, options)); // 加载 var json = File.ReadAllText(settings.Filepath); return JsonSerializer.Deserialize<MQSettings>(json, options) ?? new MQSettings();
使用Newtonsoft.Json时,可配置ContractResolver支持internal成员:
var jsonSettings = new JsonSerializerSettings { ContractResolver = new DefaultContractResolver { DefaultMembersSearchFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance }, Formatting = Formatting.Indented };
单例维护
你当前用LoadedData静态类持有实例的方式完全可行,确保启动时仅加载一次:
internal static class LoadedData { internal static MQSettings Settings { get; } = Tools.Settings.Load(); }
内容的提问来源于stack exchange,提问作者Madax
相关产品推荐
相关产品推荐

