一个强大易用的配置类: DictionaryHelper
郝伟 2022/01/30
在Windows平台进行配置读取时,通常使用系统提供的系统提供的ini的读取API:
[DllImport("kernel32")]
private static extern bool GetPrivateProfileString(string lpApplicationName, string lpKeyName, string lpDefault, StringBuilder lpReturnedString, int nSize, string lpFileName);
[DllImport("kernel32")]
private static extern bool WritePrivateProfileString(string lpApplicationName, string lpKeyName, string lpString, string lpFileName);
使用这两个函数进行进行文件读取,具有以下问题:
另外,记录通用使用字典表示,即使用key-value表示,这也会存在问题:
为解决以上问题,特编写此类。
本类名为 DictionaryHelper,内部使用字典表示,提供了一系列的方法进行操作。主要使用方法参考以下示例。
static void DictionaryTest() { // 直接初始化一个新对象。 var dict = new DictionaryHelper(); // 也可以从一个文件中初始化。 dict = new DictionaryHelper ("config.dict"); // 读取值,两种方式,具体可以对比v5和v6 var v1 = dict.GetInt(cf.port, 0); var v2 = dict.GetFloat(cf.Temperature, 0); var v3 = dict.GetDouble(cf.TestValue, 0); var v4 = dict.GetDateTime("LastUpdateTime"); var v5 = dict.GetBoolean(cf.ShowConfig); var v6 = dict[cf.ShowConfig]; Console.WriteLine($"v1={v1},\ttype={v1.GetType().Name}"); Console.WriteLine($"v2={v2},\ttype={v2.GetType().Name}"); Console.WriteLine($"v3={v3},\ttype={v3.GetType().Name}"); Console.WriteLine($"v4={v4},\ttype={v4.GetType().Name}"); Console.WriteLine($"v5={v5},\ttype={v5.GetType().Name}"); Console.WriteLine($"v6={v6},\ttype={v6.GetType().Name}\n"); // 设置值,有以下两种方式 // 方式1:直接使用字符串赋值 dict["Name"]="Jack"; dict[cf.port] = 10082 + ""; // 方式2:使用SetValue方式 dict.SetValue("FinalValue", 15.232); dict.SetValue("CurrentDate", DateTime.Now); // 输出为配置文件 Console.WriteLine(dict.ToCSharpString() + "\n"); // 保存为config.dict dict.Save("config.dict"); }
可以得到以下输出
v1=10082, type=Int32
v2=39.2, type=Single
v3=192.5322, type=Double
v4=2021/10/15 15:35:22, type=DateTime
public class cf
{
public static string ip = "ip";
public static string port = "port";
public static string user = "user";
public static string pwd = "pwd";
public static string mapping1 = "mapping1";
public static string mapping2 = "mapping2";
public static string Name = "Name";
public static string LastUpdateTime = "LastUpdateTime";
public static string Temperature = "Temperature";
public static string TestValue = "TestValue";
public static string ShowConfig = "ShowConfig";
}
通过调用 ToCSharpString() 方法,可以生成文件 cf.cs 类,可以添加到程序中,用于方便代码输入,具体内容如下。这样使用 cf.ip 就可以表示 “ip”。
public class cf { public static string ip = "ip"; public static string port = "port"; public static string user = "user"; public static string pwd = "pwd"; public static string mapping1 = "mapping1"; public static string mapping2 = "mapping2"; public static string Name = "Name"; public static string LastUpdateTime = "LastUpdateTime"; public static string Temperature = "Temperature"; public static string TestValue = "TestValue"; public static string ShowConfig = "ShowConfig"; }
以下是输出的 config.dict 文件。
ip=192.168.14.53
port=10082
user=administrator
pwd=123456
mapping1=C:\data\CTL01|/root/CTL/01
mapping2=C:\data\CTL02|/root/CTL/01
Name=Jack
LastUpdateTime=2021-10-15 15:35:22
以下为 DictionaryHelper.cs 类的源代码。
using System.IO; using System.Collections.Generic; using System.Text; using System; /// <summary> /// 用于从字符中加载数据。 /// </summary> public class DictionaryHelper { /// <summary> /// 用于存储变量的值。 /// </summary> Dictionary<string, string> dict = new Dictionary<string, string>(); string configFilepath = "config.dict"; /// <summary> /// 配置文件路径,使用的格式为字典。 /// </summary> public string ConfigFilepath { get => configFilepath; } /// <summary> /// 将输入字符串解析为int,如果解析成功,返回解析值,否则返回defaultValue(默认值为-1)。 /// </summary> /// <param name="key">输入字符串</param> /// <param name="defaultValue">默认值,解析失败时返回此值。</param> /// <returns></returns> public int GetInt(string key, int defaultValue = -1) { var value = this[key]; return value != null && int.TryParse(value, out int v) ? v : defaultValue; } /// <summary> /// 将输入字符串解析为float,如果解析成功,返回解析值,否则返回defaultValue(默认值为-1)。 /// </summary> /// <param name="key">输入字符串</param> /// <param name="defaultValue">默认值,解析失败时返回此值。</param> /// <returns></returns> public float GetFloat(string key, float defaultValue = -1) { var value = this[key]; return value != null && float.TryParse(value, out float v) ? v : defaultValue; } /// <summary> /// 将输入字符串解析为double,如果解析成功,返回解析值,否则返回defaultValue(默认值为-1)。 /// </summary> /// <param name="key">输入字符串</param> /// <param name="defaultValue">默认值,解析失败时返回此值。</param> /// <returns></returns> public double GetDouble(string key, double defaultValue = -1) { var value = this[key]; return value != null && double.TryParse(value, out double v) ? v : defaultValue; } /// <summary> /// 将输入字符串解析为 boolean,如果解析成功,返回解析值,否则返回defaultValue(默认值为false)。 /// 为了保证使用更方便,结果为 true 时不区别大小写,或者结果为1也可以。 /// </summary> /// <param name="key">输入字符串</param> /// <param name="defaultValue">默认值,解析失败时返回此值。</param> /// <returns></returns> public bool GetBoolean(string key, bool defaultValue = false) { var value = this[key]; return value != null && (value.ToLower() == "true" || value == "1") ? true : defaultValue; } /// <summary> /// 将输入字符串解析为 DateTime,如果解析成功,返回解析值,否则返回 DateTime.MinValue。 /// </summary> /// <param name="key">输入字符串</param> /// <returns></returns> public DateTime GetDateTime(string key) { var v = dict[key]; DateTime dt = DateTime.MinValue; try { dt = DateTime.Parse(v); } catch { } return dt; } /// <summary> /// 初始化空字典,不进行任何加载。 /// </summary> public DictionaryHelper() { } /// <summary> /// 使用dictfile初始化,如果失败则返回 new Dictionary<string, string>对象。 /// </summary> /// <param name="dictfile"></param> public DictionaryHelper(string dictfile) { configFilepath = dictfile; Load(configFilepath); } /// <summary> /// 返回所有的密钥,只读属性,每次返回新实例,修改不会影响原Keys。 /// </summary> public List<string> Keys { get { List<string> keys = new List<string>(); foreach (string key in dict.Keys) keys.Add(key); return keys; } } /// <summary> /// 字典中是否包括指定的值。 /// </summary> /// <param name="key"></param> /// <returns></returns> public bool ContainsKey(string key) => key !=null && dict.ContainsKey(key); /// <summary> /// 如果字典dict中包括key,则返回 dict[key],否则返回null /// </summary> /// <param name="key">访问的键。</param> /// <returns></returns> public string this[string key] { get => key != null && dict != null && dict.ContainsKey(key) ? dict[key] : null; set { // Dictionary 类可以直接使用 dict[key]=value 的方式添加,【无论key是否存在!】 if (value != null) dict[key] = value; } } /// <summary> /// 将目标对象object以键key赋值给字典。 /// </summary> /// <param name="key">键值名。</param> /// <param name="value">数据对象。</param> public void SetValue(string key, object value) { if (value != null) this[key] = value.ToString(); } /// <summary> /// 从文件中加载数据内容,加载失败则字典内容为空,但不是null。 /// </summary> /// <param name="configfile">默认为空,使用 ConfigFilepath 进行加载,如果不存在,则为空字典,但不是null。</param> public void Load(string configfile = null) { dict = LoadDictionary(configfile == null ? ConfigFilepath : configfile); dict = dict == null ? new Dictionary<string, string>() : dict; } /// <summary> /// 将文件 /// </summary> /// <param name="filepath"></param> public void Save(string filepath) { StringBuilder sb = new StringBuilder(); foreach (var key in dict.Keys) sb.AppendLine($"{key}={dict[key]}"); File.WriteAllText(filepath, sb.ToString(), Encoding.UTF8); } /// <summary> /// 根据当前类,生成用于访问的CS类。 /// </summary> /// <returns></returns> public string ToCSharpString(string className = "cf") { StringBuilder sb = new StringBuilder(); sb.AppendLine($"public class {className}"); sb.AppendLine("{"); foreach (var key in dict.Keys) sb.AppendLine($" public static string {key} = \"{key}\";"); sb.AppendLine("}"); return sb.ToString(); } /// <summary> /// 从文件中加载字典,加载失败则返回null。 /// </summary> /// <param name="configFile"></param> public static Dictionary<string, string> LoadDictionary(string configFile, char separator = '=', string encoding = "UTF-8") { // 文件如果不存在则返回null。 var dicfile = Path.GetFullPath(configFile); if (!File.Exists(dicfile)) return null; Dictionary<string, string> dic = new Dictionary<string, string>(); foreach (var row in File.ReadAllLines(dicfile)) { // 如果右侧有空格,则会被清除 var rowdata = row.TrimStart(); // 如果是注释(以#或//开头的行),则跳过 if (rowdata.StartsWith("#") || rowdata.StartsWith("//")) continue; // 定位 int pos = row.IndexOf('='); if (pos < 0 || pos >= row.Length) continue; // 解析出Key和Value进行添加 string key = row.Substring(0, pos); string value = row.Substring(pos + 1); if (!dic.ContainsKey(key)) dic.Add(key, value); } return dic; } }