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

如何在C#中优雅实现静态单例泛型?避免重复编写配置读取方法

优化配置读取逻辑的实现方案

可以通过泛型工具类+特性标记的方式彻底消除重复的配置读取代码,同时解决静态成员归属的问题,具体实现如下:

1. 定义配置文件路径特性

用特性标记每个配置类对应的JSON文件路径,实现路径与读取逻辑解耦:

[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public class ConfigFilePathAttribute : Attribute
{
    public string Path { get; }

    public ConfigFilePathAttribute(string path)
    {
        Path = path;
    }
}

2. 实现泛型配置读取工具类

利用泛型静态类的特性(每个泛型类型拥有独立的静态成员),结合Lazy<T>实现线程安全的延迟加载,统一处理配置读取逻辑:

using Microsoft.Extensions.Configuration;
using System;
using System.Reflection;

public static class ConfigReader<T> where T : class, new()
{
    private static readonly Lazy<IConfiguration> _configuration;
    private static readonly Lazy<T> _configInstance;

    static ConfigReader()
    {
        var filePathAttr = typeof(T).GetCustomAttribute<ConfigFilePathAttribute>();
        if (filePathAttr == null)
        {
            throw new InvalidOperationException($"类型 {typeof(T).Name} 未标记 ConfigFilePathAttribute");
        }

        // 延迟初始化配置构建器
        _configuration = new Lazy<IConfiguration>(() =>
            new ConfigurationBuilder()
                .AddJsonFile(filePathAttr.Path, optional: true, reloadOnChange: true)
                .Build());

        // 延迟初始化并绑定配置实例
        _configInstance = new Lazy<T>(() =>
        {
            var instance = new T();
            _configuration.Value.Bind(instance);
            return instance;
        });
    }

    public static T GetValue() => _configInstance.Value;
}

3. 改造原有配置类

去掉重复的静态成员和GetValue方法,仅保留配置属性并标记对应文件路径:

ApiPath 配置类

[ConfigFilePath("Config/ApiPath.json")]
public class ApiPath
{
    public string GetCookieAPi { get; set; }
    public string CheckCookieAPi { get; set; }
}

ConfigValue 配置类

[ConfigFilePath("Config/Config.json")]
public class ConfigValue
{
    public string ServerIP { get; set; }
    public string MongoDbStr { get; set; }
    public int CookieIntervals { get; set; }
}

4. 使用方式

直接通过泛型工具类获取配置实例,无需关注底层读取逻辑:

// 获取ApiPath配置
var apiPathConfig = ConfigReader<ApiPath>.GetValue();
// 获取ConfigValue配置
var configValue = ConfigReader<ConfigValue>.GetValue();

方案优势

  • 消除重复代码:所有配置类无需重复实现读取逻辑,仅需定义属性和标记路径
  • 线程安全:Lazy<T>保证初始化过程线程安全,避免多线程环境下的重复构建问题
  • 缓存机制:每个配置类型的实例和IConfiguration仅初始化一次,提升性能
  • 灵活性:通过特性标记路径,后续新增配置类只需添加特性即可,扩展性强

内容的提问来源于stack exchange,提问作者Phonex Alica

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 19:01:35