惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

W
WeLiveSecurity
T
Tenable Blog
Project Zero
Project Zero
C
Cybersecurity and Infrastructure Security Agency CISA
T
The Exploit Database - CXSecurity.com
P
Palo Alto Networks Blog
S
Schneier on Security
Scott Helme
Scott Helme
S
Securelist
Know Your Adversary
Know Your Adversary
Vercel News
Vercel News
IT之家
IT之家
V
V2EX
F
Fortinet All Blogs
Simon Willison's Weblog
Simon Willison's Weblog
K
Kaspersky official blog
博客园_首页
T
Tailwind CSS Blog
The GitHub Blog
The GitHub Blog
Spread Privacy
Spread Privacy
Microsoft Security Blog
Microsoft Security Blog
Cisco Talos Blog
Cisco Talos Blog
The Register - Security
The Register - Security
有赞技术团队
有赞技术团队
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Cyberwarzone
Cyberwarzone
Google DeepMind News
Google DeepMind News
The Hacker News
The Hacker News
L
LINUX DO - 热门话题
Hugging Face - Blog
Hugging Face - Blog
博客园 - 三生石上(FineUI控件)
A
Arctic Wolf
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
C
CXSECURITY Database RSS Feed - CXSecurity.com
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
T
Threat Research - Cisco Blogs
P
Proofpoint News Feed
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
P
Privacy & Cybersecurity Law Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
C
CERT Recently Published Vulnerability Notes
S
SegmentFault 最新的问题
AWS News Blog
AWS News Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
罗磊的独立博客
Apple Machine Learning Research
Apple Machine Learning Research
P
Proofpoint News Feed
The Cloudflare Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
V
Vulnerabilities – Threatpost

博客园 - Louis.Lu.Sz

在C#中,如果声明字段时不加关键字volatile,会影响多线程环境中对该字段的访问吗? Win10, Win11 Ping不通 FastReport使用笔记 Windows窗体控件库的小秘密 在windows桌面显示IP等信息的小工具分享 oracle,根据查询结果结构创建新表 Oracle多表关联如何更新多个字段 【转】Android程序右上角不显示3个点的菜单 Visual studio项目调试时提示“ 你正在调试XXXX的发布版本。” 【原】记录一下第一次使用Python简单处理Excel 【原创】分享一种WPF列表数据的分页打印方案 [原创] 分享一种Asp.NetMVC WebApi作为后端技术结合Vue前端框架开发时开发环境的优雅配置方案 [原] c# winform controls 查找指定类型子控件的扩展方法 [转]Errors while building APK. You can find the errors in the 'Messages' view.解决办法 [转]oracle数据库转mysql数据库 SaveFileDialog下载模板文件 算法:把一个数字拆分成指定数字的和,允许数字个数为0和重复 WPF简单实现可以左右滑动的CheckBox复选框,样式模仿的微信 WPF里借助附加属性让DataGrid显示行号
我想实现一个通用的配置读写类
Louis.Lu.Sz · 2021-02-07 · via 博客园 - Louis.Lu.Sz

一个项目,

有一些配置,

不想写死,想用一个配置文件管理,需要读写这个配置文件。

写完了之后,看着一大堆代码,进入了反思,“我是不是自我矛盾了,说了不想写死,还是写了一个死的配置文件读写类,能不能通用一点呢,能不能搞个单例模式控制一下全局访问点呢,……“

肯定能,通用的单例实现,我见过,懒得写了,直接网上搜索了一下 :) 。

通用呢,我也不想太发散,做了如下约定:

配置文件以json文件存放在App_Data文件夹下(我现在做的是ASP.NET MVC项目,其它项目,后续再适当调整吧,大同小异),

然后,每个配置文件名,就用配置类的类名。

基本上整体代码都没什么问题,只有一个问题,让我搞了关天,那就是:

之前,我把初始化的代码,即对json配置文件反序列化的代码写在配置类实例化后就会执行的地方(比如默认构造函数内,或者是会由默认构造函数调用的其它函数内),会导到JSON反序列化时,发生异常,

进入一个死循环”实例化,初始化,反序列化,……“。

后来我把这个初始化的代码单独拿出来,在单例实例化之后调用,而不是具体配置类实例化的地方调用,从而解决了这个问题。

看着这些文字,有点晕,算了,直接上代码吧。

//用于实现通用单例和隔离类初始化方法的代码
    /// <summary>
    /// 不支持非公共的无参构造函数的
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class BaseInstance1<T> where T : class, new()
    {
        private readonly static object lockObj = new object();
        private static T instance = null;
        public static T Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (lockObj)
                    {
                        if (instance == null)
                        {
                            instance = new T();
                        }
                    }
                }
                return instance;
            }
        }
    }

    /// <summary>
    /// 支持非公共的无参构造函数的
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class BaseInstance2<T> where T : class, IInitable //new(),new不支持非公共的无参构造函数 
    {
        /*
         * 单线程测试通过!
         * 多线程测试通过!
         * 根据需要在调用的时候才实例化单例类!
        */
        private static T _instance;
        private static readonly object SyncObject = new object();
        public static T Instance
        {
            get
            {
                if (_instance == null)//没有第一重 singleton == null 的话,每一次有线程进入 GetInstance()时,均会执行锁定操作来实现线程同步,
                //非常耗费性能 增加第一重singleton ==null 成立时的情况下执行一次锁定以实现线程同步
                {
                    lock (SyncObject)
                    {
                        if (_instance == null)//Double-Check Locking 双重检查锁定
                        {
                            //_instance = new T();
                            //需要非公共的无参构造函数,不能使用new T() ,new不支持非公共的无参构造函数 
                            _instance = (T)Activator.CreateInstance(typeof(T), true); //第二个参数防止异常:“没有为该对象定义无参数的构造函数。”
                            _instance.Init();
                        }
                    }
                }
                return _instance;
            }
        }
        public static void SetInstance(T value)
        {
            _instance = value;
        }
    }

    public interface IInitable
    {
        /// <summary>
        /// 带有初始化方法
        /// </summary>
        void Init();
    }
//配置基类
    /// <summary>
    /// 基础配置类,定义了配置读取的通用操作。
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class BaseConfig<T> : BaseInstance2<T> where T : class , IInitable //, new()
    {
        private string filepath = null;
        private ILog logger = null;

        /// <summary>
        /// 
        /// </summary>
        public BaseConfig()
        {
            filepath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "App_Data", $"{typeof(T).Name}.json");
        }

        /// <summary>
        /// 初始化
        /// </summary>
        public virtual void Init()
        {
            try
            {
                logger = LoggerConfig.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
                //read config file
                if (File.Exists(filepath))
                {
                    var josnstr = File.ReadAllText(filepath, System.Text.Encoding.UTF8);
                    var cfg = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(josnstr);
                    Clone(cfg);
                }
            }
            catch (Exception ex)
            {
                logger.Error("读取SysConfig配置文件时报错", ex);
            }
        }

        private void Clone(T config)
        {
            var props = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public);
            foreach (var p in props)
            {
                p.SetValue(this, p.GetValue(config));
            }
        }

        /// <summary>
        /// 保存修改
        /// </summary>
        public void Save()
        {
            try
            {
                //if (File.Exists(filepath))
                {
                    string jsonstr = Newtonsoft.Json.JsonConvert.SerializeObject(this);
                    File.WriteAllText(filepath, jsonstr);
                }
            }
            catch (Exception ex)
            {
                logger.Error("保存配置文件时报错", ex);
            }
        }

    }
/// <summary>
    /// 系统配置
    /// </summary>
    public class SysConfig : BaseConfig<SysConfig>, IInitable
    {
        private SysConfig() { }
        public override void Init()
        {
            base.Init();
        }

        /// <summary>
        /// 配置字段1
        /// </summary>
        public int XXXCount { get; set; } = 5;

        /// <summary>
        /// 配置字段2
        /// </summary>
        public int YYYCount { get; set; } = 6;

    }
//测试代码
public ActionResult ShowSysConfig()
        {
            //var cfg1 = new SysConfig();
            var cfg = SysConfig.Instance;
            var jsonstr = Newtonsoft.Json.JsonConvert.SerializeObject(cfg);

            return Content(jsonstr, "application/json");
        }

        public ActionResult ChangeSysConfig()
        {
            var cfg = SysConfig.Instance;
            cfg.XXXCount += 1;
            cfg.YYYCount += 1;
            SysConfig.Instance.Save();

            return ShowSysConfig();
        }