在 .NET中,一种更方便操作配置项的方法

在应用程序的开发过程中,我们往往会为软件提供一些配置项,以允许软件根据配置项灵活来做事情,比如配置日志文件路径等,此外,我们还可以用配置项来为用户存储其偏好设置等。

.NET 为我们默认提供了配置机制以及配置文件,项目中的 app.config 或者 web.config 文件(如果没有,可以添加)就是 .NET 为我们提供的配置文件。在这个配置文件中的根节点 configuration 下,创建 appSettings 节点,在此节点中,我们可以添加自义定的配置项。同时,ConfigurationManager 类提供了访问及操作此配置文件(由 Configuration 类代表)中配置的方法。需要注意的是,这个类在 System.Configuration.dll 文件中,需要将它添加到项目的引用中,才能使用。

本文主要介绍一种更为便利的方式来访问/存储配置项,当然,它本质上是使用 ConfigurationManager 类完成的。它主要的特点是以面向对象的方式来解决此问题,更具体地说,我们创建一个类,类中包括一些属性用以表示配置项,通过访问或设置这些属性,即可得到或更新对应的配置项。

一、实现

首先,我们为 Configuration 类添加一个扩展方法 AddOrUpdateAppSettingItem,如下 :

        /// <summary>
        /// 向配置的 AppSetings 节添加(如果不存在)或更新(如果已存在)给定的 key 和 value
        /// </summary>
        /// <param name="config"></param>
        /// <param name="key"></param>
        /// <param name="value"></param>
        public static void AddOrUpdateAppSettingItem(this Configuration config, string key, string value)
        {
            if (config.AppSettings.Settings.AllKeys.Contains(key))
            {
                config.AppSettings.Settings[key].Value = value;
            }
            else
            {
                config.AppSettings.Settings.Add(key, value);
            }
        }
    }

这个方法主要实现了向 appSettings 节点添加(配置项不存在)或更新(配置项已存在)配置,接下来我们会用到这个方法。

接着,我们定义抽象基类 ConfigSetting,如下:

    public abstract class ConfigSetting
    {
        /// <summary>
        /// 配置类
        /// </summary>
        /// <param name="configuration">配置</param>
        public ConfigSetting(Configuration configuration)
        {
            Configuration = configuration;
        }

        /// <summary>
        /// 当前配置
        /// </summary>
        public Configuration Configuration
        {
            get;
        }

        /// <summary>
        /// 获取当前程序配置
        /// </summary>
        /// <param name="config"></param>
        /// <returns></returns>
        public static Configuration GetCurrentConfiguration()
        {
            return ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
        }

        /// <summary>
        /// 返回指定的配置项的值
        /// </summary>
        /// <param name="settingKey"></param>
        /// <returns></returns>
        protected virtual string GetSettingValue([CallerMemberName] string settingKey = null)
        {
            return Configuration?.AppSettings?.Settings[settingKey]?.Value;
        }

        /// <summary>
        /// 返回指定的配置项的值
        /// </summary>
        /// <typeparam name="T">值类型</typeparam>
        /// <param name="settingKey"></param>
        /// <returns></returns>
        protected virtual T GetSettingValue<T>([CallerMemberName] string settingKey = null)
        {
            var value = GetSettingValue(settingKey);

            if (string.IsNullOrWhiteSpace(value))
            {
                return default(T);
            }
            else
            {
                return (T)Convert.ChangeType(value, typeof(T));
            }
        }

        /// <summary>
        /// 为指定的配置项设置值
        /// </summary>
        /// <param name="value"></param>
        /// <param name="settingKey"></param>
        protected virtual void SetSettingValue(object value, [CallerMemberName] string settingKey = null)
        {
            Configuration.AddOrUpdateAppSettingItem(settingKey, value?.ToString());
            Configuration.Save();
        }
    }

其中主要包括了一个静态方法和三个受保护的 virtual 方法,说明:

1. 静态方法 GetCurrentConfiguration 返回当前应用的配置类;
2. GetSettingValue 和 SetSettingValue 方法则分别负责读取、设置指定配置项的值;
3. GetSettingValue 有两个重载,其中一个用于支持泛型;
4. 在它们的方法签名中包括 CallerMemberName 特性,通过这个属性可以得到调用此访问的方法或属性的名称。

然后,创建一个名为 AppConfigSetting 的类,这个类将会包括一些代表配置项的属性,并且它要继承自 ConfigSetting,如下:

    public class AppConfigSetting : ConfigSetting
    {
        public AppConfigSetting(Configuration configuration) : base(configuration)
        {

        }

        public DateTime InstallDateTime
        {
            get { return GetSettingValue<DateTime>(); }
            set { SetSettingValue(value); }
        }

        public string LogFileName
        {
            get { return GetSettingValue(); }
            set { SetSettingValue(value); }
        }

        public int ReadBlockSize
        {
            get { return GetSettingValue<int>(); }
            set { SetSettingValue(value); }
        }
    }

说明:

1. 可以看到我们在其中增加了三个属性。而在它们的 get 与 set 段中,调用了基类中的对应的两个方法,其中,对于非 string 类型的配置项,我们调用的是 GetSettingValue<T>。
2. 通过我们前面提到的 CallerMemberName 特性,就可以得到这里的属性名,并得到相应的配置项,这样我们就无需硬编码。所以,这个属性名,本质上就是配置项的名称。

这样,我们将所有要用到的配置项作为属性放到 AppConfigSetting 类中,再用操作这些属性就可以了完成所有对配置项的操作了。

二、如何使用

使用它,也非常简单,代码如下:

            var config = ConfigSetting.GetCurrentConfiguration();
            AppConfigSetting setting = new AppConfigSetting(config);

            // 未设置时
            MessageBox.Show($"LogFileName: {setting.LogFileName}");

            // 设置后,再读取
            setting.LogFileName = "log.txt";
            MessageBox.Show($"LogFileName: {setting.LogFileName}");

三、补充

为了满足在不向 AppConfigSetting 添加配置项属性,但却又要访问/存储指定配置项的需要,我们可以在基类 ConfigSetting 中添加以下三个方法:

        /// <summary>
        /// 返回指定的配置项的值
        /// </summary>
        /// <param name="settingKey"></param>
        /// <returns></returns>
        public string GetSettingValueByKey(string settingKey)
        {
            return GetSettingValue(settingKey);
        }

        /// <summary>
        /// 返回指定的配置项的值
        /// </summary>
        /// <param name="settingKey"></param>
        /// <returns></returns>
        public T GetSettingValueByKey<T>(string settingKey)
        {
            return GetSettingValue<T>(settingKey);
        }

        /// <summary>
        /// 为指定的配置项设置值
        /// </summary>
        /// <param name="value"></param>
        /// <param name="settingKey"></param>
        public void SetSettingValueByKey(string settingKey, object value)
        {
            SetSettingValue(value, settingKey);
        }

使用这几个方法,可以自由地访问/存储配置项,不同于上面增加属性方式的是,它需要自己传递配置项 key 作参数。

使用:

            // 未设置时
            MessageBox.Show($"LogLevel: {setting.GetSettingValueByKey("LogLevel")}");

            // 设置后,再读取
            setting.SetSettingValueByKey("LogLevel", 5);
            MessageBox.Show($"LogLevel: {setting.GetSettingValueByKey("LogLevel")}");

总结

本文主要介绍了一种访问应用程序配置更为便利的方式,其主要思想是通过基类中 GetSettingValue/SetSettingValue 两个方法借助于 CallerMemberName 特性而得到派生类中属性的名称而操作对应的配置项。当然,这里不仅提供了一种方法,更是提供一种思路,基于此,你还可以根据实际需要来调整、扩展以满足你的实际需要。

源码下载

原文地址:https://www.cnblogs.com/wpinfo/p/config_setting.html

时间: 2024-08-05 05:51:07

在 .NET中,一种更方便操作配置项的方法的相关文章

【转】寻求一种更好的软件工程研究方法

Mary Shaw 寻求一种更好的软件工程研究方法 Mary Shaw School of Computer Science, Carnegie Mellon University 摘要关于对物理学,生物学和医学的研究过程,人们早已有了公开的精准的解释.即便是在形式上看似简单,但这个领域的内和外也算提供了有价值的“高水准研究”的指导.但是软件工程就不同了,人们至今尚未明确找到并解释如何研究以及用何种方法去进行研究??.(方法论也是顶层设计,只有找到了高屋建瓴的研究方法,才能推动这个行业的进步.本

几种通过JDBC操作数据库的方法,以及返回数据的处理

1.SQL TO String :只返回一个查询结果 例如查询某条记录的总数 rs = stmt.executeQuery(replacedCommand);             if (rs != null && rs.next()) // rs only contains one row and one column             {                    String tempStr = rs.getString(1);                 

unity中三种调用其他脚本函数的方法

第一种,被调用脚本函数为static类型,调用时直接用  脚本名.函数名().很不实用-- 第二种,GameObject.Find("脚本所在物体名").SendMessage("函数名");  此种方法可以调用public和private类型函数 第三种,GameObject.Find("脚本所在物体名").GetComponent<脚本名>().函数名();此种方法只可以调用public类型函数 unity中三种调用其他脚本函数的

Android中8种异步处理与计算的方法

注:该文章翻译自Ali Muzaffar的文章<8 ways to do asynchronous processing in Android and counting>  Android提供了许多API来支持异步处理的功能,结合着Java提供的方法和你手上拥有的,估计目前已经有数十种进行异步任务的方法. 目前的趋势是仅使用Java的threads或者Android的AsyncTask来处理各种问题.虽然上述两种方法拥有较高的知名度,但是并非所有的API都适合,为你的需求选择最合适的方法能够使

分享php中四种webservice实现的简单架构方法及实例

一:PHP本身的SOAP所有的webservice都包括服务端(server)和客户端(client).要使用php本身的soap首先要把该拓展安装好并且启用.下面看具体的code首先这是服务端实现: PHP Code复制内容到剪贴板 <?php class test { function show() { return 'the data you request!'; } } function getUserInfo($name) { return 'fbbin'; } //实例化的参数手册上

Python中几种数据的常用内置方法

1. int bit_lenth:二进制的长度 2.str capitalize():首字母大写,其他小写. upper():全部转换为大写,lower()相反;casefold()功能类似于lower,但是更强大,不常用 title():每个被特殊字符隔开的单词的首字母大写,其中中文属于特殊字符; strip():去除左边和有右边的空格,对中间的空格无能为力,也可以去掉两边的指定的字符串 replace(a, b):将a替换为b split(a):用a作为切割线进行切割,返回值为一个list

lua中,两种json和table互转方法的效率比较

lua中json和table的互转,是我们在平时开发过程中经常用到的.比如: 在用lua编写的服务器中,如果客户端发送json格式的数据,那么在lua处理业务逻辑的时候,必然需要转换成lua自己的数据结构,如table.此时,就会用到table和json格式的互转. 在用lua编写的服务器中,如果我们通过redis来存储数据,由于redis中不存在table这种数据结构,因此,我们可以选择将table转换成json字符串来进行存储.在数据的存取过程中,也会用到table和json格式的互转. 以

比较C#中几种常见的复制字节数组方法的效率[转]

[原文链接] 在日常编程过程中,我们可能经常需要Copy各种数组,一般来说有以下几种常见的方法:Array.Copy,IList<T>.Copy,BinaryReader.ReadBytes,Buffer.BlockCopy,以及System.Buffer.memcpyimpl,由于最后一种需要使用指针,所以本文不引入该方法. 本次测试,使用以上前4种方法,各运行1000万次,观察结果. using System; using System.Collections.Generic; using

tensorflow中一种融合多个模型的方法

1.使用场景 假设我们有训练好的模型A,B,C,我们希望使用A,B,C中的部分或者全部变量,合成为一个模型D,用于初始化或其他目的,就需要融合多个模型的方法 2.如何实现 我们可以先声明模型D,再创建多个Saver实例,分别从模型A,B,C的保存文件(checkpoint文件)中读取所需的变量值,来达成这一目的,下面是示例代码: 首先创建一个只包含w1,w2两个变量的模型,初始化后保存: 1 def train_model1(): 2 w1 = tf.get_variable("w1"