C#自定义特性实现:基于特性的配置存取解耦方案咨询
实现基于自定义特性的AppSettings自动读写方案
1. 定义自定义标记特性
先创建一个特性类,用来标记需要参与AppSettings读写的属性,支持自定义配置项键名(默认用属性名):
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] public class AppSettingAttribute : Attribute { // 可选:指定AppSettings中的键名,未指定则使用属性名称 public string Key { get; } public AppSettingAttribute(string key = null) { Key = key; } }
2. 编写通用配置读写工具类
通过反射遍历目标对象的属性,自动完成与ConfigurationManager.AppSettings的交互,完全解耦工具类和业务数据类:
using System.Configuration; using System.Reflection; public static class AppSettingsHandler { // 从AppSettings加载配置到目标对象 public static void Load(object target) { if (target == null) throw new ArgumentNullException(nameof(target)); var targetType = target.GetType(); var targetProperties = targetType.GetProperties(BindingFlags.Public | BindingFlags.Instance) .Where(p => p.GetCustomAttribute<AppSettingAttribute>() != null); foreach (var prop in targetProperties) { var attr = prop.GetCustomAttribute<AppSettingAttribute>(); var configKey = attr.Key ?? prop.Name; var configValue = ConfigurationManager.AppSettings[configKey]; if (configValue != null) { // 处理基础类型的转换,可扩展支持枚举、DateTime等 var convertedValue = Convert.ChangeType(configValue, prop.PropertyType); prop.SetValue(target, convertedValue); } } } // 将目标对象的属性保存到AppSettings public static void Save(object target) { if (target == null) throw new ArgumentNullException(nameof(target)); var targetType = target.GetType(); var targetProperties = targetType.GetProperties(BindingFlags.Public | BindingFlags.Instance) .Where(p => p.GetCustomAttribute<AppSettingAttribute>() != null); var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); foreach (var prop in targetProperties) { var attr = prop.GetCustomAttribute<AppSettingAttribute>(); var configKey = attr.Key ?? prop.Name; var propValue = prop.GetValue(target)?.ToString(); if (propValue != null) { if (config.AppSettings.Settings[configKey] != null) config.AppSettings.Settings[configKey].Value = propValue; else config.AppSettings.Settings.Add(configKey, propValue); } } config.Save(ConfigurationSaveMode.Modified); ConfigurationManager.RefreshSection("appSettings"); } }
3. 业务类使用示例
直接用特性标记需要持久化的属性,无需实现任何接口:
public class UserPreferences { [AppSetting] // 默认使用属性名"Nickname"作为配置键 public string Nickname { get; set; } [AppSetting("Login_RetryLimit")] // 自定义配置键名 public int MaxRetryTimes { get; set; } [AppSetting] public bool AutoSync { get; set; } [AppSetting] public double VolumeLevel { get; set; } }
读写配置的调用方式:
// 加载配置到对象 var userPrefs = new UserPreferences(); AppSettingsHandler.Load(userPrefs); // 修改后保存配置 userPrefs.AutoSync = true; AppSettingsHandler.Save(userPrefs);
4. 可选扩展优化
- 复杂类型支持:针对枚举、DateTime等类型,可在
Load方法中增加类型判断逻辑,手动实现转换;也可以定义类型转换器接口,通过特性指定转换器。 - 必填项校验:在
AppSettingAttribute中增加IsRequired属性,加载时若配置项缺失则抛出异常。 - 反射缓存:如果频繁调用读写方法,可缓存目标类型的属性信息,避免重复反射的性能开销。
内容的提问来源于stack exchange,提问作者Hamhub7
相关产品推荐
相关产品推荐

