一个项目,

有一些配置,

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

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

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

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

配置文件以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();
        }

  

posted on 2021-02-07 11:31  Louis.Lu.Sz  阅读(98)  评论(0编辑  收藏  举报