You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 17:18:18