我一般写ini,很少直接操作config,以后还是多按照微软的方式来,下次使用心得贴上与大家一起共享,以下来自网络
说了对配置文件的修改,基本上都已经是全部了,后来也补充了SingleTagSectionHandler的访问,现在把对SingleTagSectionHandler的写以及一些能偷懒的方法一起说下,希望大家有好东西都能够分享下,有时用到了,就是好东西,不用到就当作是学习吧
提供二个访问配置文件的静态方法
/// <summary> /// 打开默认的配置文件.exe.config /// </summary> /// <returns></returns> public static Configuration GetConfiguration() { return ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); }/// <summary>
/// 获取指定的配置文件。 /// </summary> /// <param name="configFullPath">配置文件的全名称</param> /// <returns></returns> public static Configuration GetConfiguration(string configFullPath) { ExeConfigurationFileMap configFile = new ExeConfigurationFileMap(); configFile.ExeConfigFilename = configFullPath; Configuration config = ConfigurationManager.OpenMappedExeConfiguration(configFile, ConfigurationUserLevel.None); return config; }通过上两个静态方法可以获取到Configuration实例
获取SingleTagSectionHandler节点的值的多个方法
/// <summary> /// 获取SingleTagSectionHandler某节点的值。 /// </summary> /// <param name="config"></param> /// <param name="sectionName"></param> /// <param name="property"></param> /// <returns></returns> public static string GetSingleTagSectionItemValue(this Configuration config, string sectionName, string property) { Dictionary<string, string> dict = GetSingleTagSectionValues(config, sectionName); if (dict != null && dict.Count > 0) { if (dict.ContainsKey(property)) return (string)dict[property]; } return null; }/// <summary>
/// 获取SingleTagSectionHandler节点的值。 /// </summary> /// <param name="config"></param> /// <param name="sectionName"></param> /// <returns></returns> public static Dictionary<string, string> GetSingleTagSectionValues(this Configuration config, string sectionName) { var section = config.GetSection(sectionName); if (section == null || section.SectionInformation == null) return null; ConfigXmlDocument xdoc = new ConfigXmlDocument(); xdoc.LoadXml(section.SectionInformation.GetRawXml()); System.Xml.XmlNode xnode = xdoc.ChildNodes[0];Dictionary<string, string> result = new Dictionary<string, string>();
IDictionary dict = (IDictionary)(new SingleTagSectionHandler().Create(null, null, xnode)); foreach (string str in dict.Keys) { result[str] = (string)dict[str]; }return result;
}更新SingleTagSection只能通过Xml来实现,在些使用了ConfigXmlDocument类,通过更改DefaultSection的SectionInfomation的RawXml来完成,同时更改SectionInformation.Type为SingleTagSectionHandler的完全限定名。
更新和删除
/// <summary> /// 更新配置节,相同的就修改,没有的就增加。 /// </summary> /// <param name="config"></param> /// <param name="sectionName"></param> /// <param name="items"></param> public static void UpdateSingleTagSectionValues(this Configuration config, string sectionName, Dictionary<string, string> items) { Dictionary<string, string> orgItem = GetSingleTagSectionValues(config, sectionName); if (orgItem == null) orgItem = new Dictionary<string, string>(); foreach (string key in items.Keys) { orgItem[key] = items[key]; } UpdateSingleTagSection(config, sectionName, orgItem); }/// <summary>
/// 删除配置点的一些配置。 /// </summary> /// <param name="config"></param> /// <param name="sectionName"></param> /// <param name="items"></param> public static void RemoveSingleTagSectionValues(this Configuration config, string sectionName, Dictionary<string, string> items) { Dictionary<string, string> orgItem = GetSingleTagSectionValues(config, sectionName); if (orgItem != null) { foreach (string key in items.Keys) { orgItem.Remove(key); } UpdateSingleTagSection(config, sectionName, orgItem); } } private static void UpdateSingleTagSection(Configuration config, string sectionName, Dictionary<string, string> items) { config.Sections.Remove(sectionName);DefaultSection section = new DefaultSection();
config.Sections.Add(sectionName, section); ConfigXmlDocument xdoc = new ConfigXmlDocument(); XmlNode secNode = xdoc.CreateNode(XmlNodeType.Element, sectionName, xdoc.NamespaceURI); xdoc.AppendChild(secNode); foreach (string key in items.Keys) { XmlAttribute attr = xdoc.CreateAttribute(key); attr.Value = items[key]; secNode.Attributes.Append(attr); } section.SectionInformation.SetRawXml(xdoc.OuterXml); section.SectionInformation.Type = typeof(SingleTagSectionHandler).AssemblyQualifiedName; config.Save(ConfigurationSaveMode.Modified); }应该还得提供一个对自定义的配置节访问和读写的方法,以更好的扩充
自定义配置节
/// <summary> /// 获取自定义的配置节。 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="config"></param> /// <param name="sectionName"></param> /// <returns></returns> public static T GetCustomSection<T>(this Configuration config, string sectionName) where T : ConfigurationSection { return (T)config.GetSection(sectionName); }/// <summary>
/// 保存自定义配置节。 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="config"></param> /// <param name="section"></param> /// <param name="sectionName"></param> public static void SaveCustomSection<T>(this Configuration config, T section, string sectionName) where T : ConfigurationSection { config.RemoveSection(sectionName); config.Sections.Add(sectionName, section); config.Save(ConfigurationSaveMode.Modified); }至于配置组,本人觉得用处不大,实现起来也很别扭,所在就不实现了,如果真的是很复杂的配置,建议自己定义一个配置节吧。
下面一些懒人的方法,本人觉得还是很不错的,至少会省掉不少的开发时间。
通过反射对实体或静态属性进行赋值,在此假设obj如果为null就使用静态属性。
反射获取属性值
private static void SetPropertiesValue(object obj, Dictionary<string, string> items, Type cfgEtyType) { BindingFlags bf = BindingFlags.Public; if (obj == null) bf |= BindingFlags.Static; else bf |= BindingFlags.Instance;PropertyInfo[] pinfos = cfgEtyType.GetProperties(bf);
foreach (PropertyInfo p in pinfos)
{ try { if (items.ContainsKey(p.Name)) { string val = items[p.Name]; if (!string.IsNullOrEmpty(val)) { if (p.PropertyType.IsEnum) { //判断是否为数字 if (isDigital(val)) { p.SetValue(obj, Enum.Parse(p.PropertyType, val, true), null); } else { //判断是否存在该名称 if (isExistEnumKey(p.PropertyType, val)) p.SetValue(obj, Enum.Parse(p.PropertyType, val, true), null); } } else if (p.PropertyType.IsValueType) //值类型 { MethodInfo minfo = p.PropertyType.GetMethod("Parse", new Type[] { typeof(string) }); if (minfo != null) { p.SetValue(obj, minfo.Invoke(null, new object[] { val }), null); } } else p.SetValue(obj, val, null); } else if (!p.PropertyType.IsEnum && !p.PropertyType.IsValueType) p.SetValue(obj, val, null); } } catch (System.Exception ex) { Console.WriteLine(ex.Message + "\n" + ex.StackTrace); } } }/// <summary>
/// 判断枚举值是否为数字 /// </summary> /// <param name="strValue"></param> /// <returns></returns> private static bool isDigital(string strValue) { return Regex.IsMatch(strValue, @"^(\d+)$"); }/// <summary>
/// 判断是否存在枚举的名称 /// </summary> /// <param name="type"></param> /// <param name="keyName"></param> /// <returns></returns> private static bool isExistEnumKey(Type type, string keyName) { bool isExist = false; foreach (string key in Enum.GetNames(type)) { if (key.Equals(keyName, StringComparison.OrdinalIgnoreCase)) { isExist = true; break; } } return isExist; }动态获取值,在此再次强调,属性值必需和配置节的Key等相同,包括大小写。
使用抽象类的静态属性来取出配置节的值
/// <summary> /// 使用反射获取实体配置节的值,实体的静态属性必需和配置的Key相同。 /// </summary> /// <param name="config">打开的配置实例</param> /// <typeparam name="T">要取值的类,类的静态属性要和Key值对应</typeparam> /// <param name="sectionName">T 对就的配置节的名称</param> public static void GetKeyValueSectionConfigValue<T>(this Configuration config, string sectionName) where T : class { try { Dictionary<string, string> dict = GetKeyValueSectionValues(config, sectionName); Type cfgEtyType = typeof(T); SetPropertiesValue(null, dict, cfgEtyType); } catch (System.Exception ex) { Console.WriteLine(ex.Message + "\n" + ex.StackTrace); } }提供几个和Configuration实例无关的辅助方法,但也作为扩展方法来实现,以方便操作,只要由实例和抽象类来获取到HashTable的值,和反过来取得实例的值
辅助方法
/// <summary> /// 由集合根据字段的属性生成实体。属性名为key,属性值为value。 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="config"></param> /// <param name="items"></param> /// <returns></returns> public static T GetConfigEntityByItems<T>(this Configuration config, Dictionary<string, string> items) where T : class { Type etyType = typeof(T); Func<object> func = etyType.CreateInstanceDelegate(); object ety = func.Invoke();SetPropertiesValue(ety, items, etyType);
return (T)ety;
}/// <summary>
/// 由实例生成配置的项。 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="config">没有实际使用到</param> /// <param name="instance"></param> /// <returns></returns> public static Dictionary<string, string> GetItemsByConfigEntity<T>(this Configuration config, T instance) where T : class { Type cfgEtyType = typeof(T); BindingFlags bf = BindingFlags.Public; if (instance == null) bf |= BindingFlags.Static; else bf |= BindingFlags.Instance; PropertyInfo[] pinfos = cfgEtyType.GetProperties(bf); Dictionary<string, string> dict = new Dictionary<string, string>();foreach (PropertyInfo p in pinfos)
{ dict[p.Name] = "" + p.GetValue(instance, null); } return dict; }/// <summary>
/// 由类的静态属性生成配置项。 /// </summary> /// <typeparam name="T"></typeparam> /// <returns></returns> public static Dictionary<string, string> GetItemsByClass<T>(this Configuration config) where T : class { return GetItemsByConfigEntity<T>(config, null); }
从appSettings获取值
/// <summary> /// 获取appSettings的配置值。Key值 和 T 的静态属性相同才能取出来。 /// </summary> /// <param name="config">打开的配置实例</param> /// <typeparam name="T">要取值的类,类的静态属性要和Key值对应</typeparam> public static void GetAppSettingsConfigValue<T>(this Configuration config) where T : class { //通过反射自动值,增加属性只需把配置的key值和属性的名称相同即可。 Type cfgType = typeof(ConfigUtility);MethodInfo getAppConfigMethod = cfgType.GetMethod("GetAppConfig", BindingFlags.Static | BindingFlags.Public);
Type etyType = typeof(T);Dictionary<string, string> items = GetAppSettings(config);
SetPropertiesValue(null, items, etyType);
}配置节的保存
保存配置节
/// <summary> /// 保存 Section 配置的值。保存为DictionarySectionHandler配置节。 /// </summary> /// <param name="config"></param> /// <typeparam name="T"></typeparam> /// <param name="sectionName"></param> public static void SaveKeyValueSectionConfig<T>(this Configuration config, string sectionName) where T : class { var orgsection = config.GetSection(sectionName); if (orgsection != null) config.Sections.Remove(sectionName);AppSettingsSection section = new AppSettingsSection();
config.Sections.Add(sectionName, section);Type etyType = typeof(T);
foreach (PropertyInfo pinfo in etyType.GetProperties(BindingFlags.Static | BindingFlags.Public)) { string keyName = pinfo.Name; object objValue = pinfo.GetValue(null, null); section.Settings.Remove(keyName); section.Settings.Add(new KeyValueConfigurationElement(keyName, "" + objValue)); } section.SectionInformation.Type = typeof(DictionarySectionHandler).AssemblyQualifiedName; config.Save(ConfigurationSaveMode.Modified); }/// <summary>
/// 保存为 AppSettings 配置的值。 /// </summary> /// <typeparam name="T"></typeparam> public static void SaveAppSettingsConfig<T>(this Configuration config) where T : class { try { Type etyType = typeof(T); foreach (PropertyInfo pinfo in etyType.GetProperties(BindingFlags.Static | BindingFlags.Public)) { string keyName = pinfo.Name;object objValue = pinfo.GetValue(null, null);
UpdateAppSettingsItemNoSave(config, keyName, "" + objValue);
}config.Save(ConfigurationSaveMode.Modified);
} catch (System.Exception ex) { Console.WriteLine(ex.Message + "\n" + ex.StackTrace); } }配置文件修改系列在此告一段落了,再附加上创建实体用到的Type的扩展,是从网络抄摘下来的,在本息用了代替Activator来创建实例,效率会快点。
using System;
using System.Collections.Generic;using System.Linq;using System.Text;using System.Linq.Expressions;namespace System
{ public static class TypeExtensions { public static Func<object> CreateInstanceDelegate(this Type type) { NewExpression newExp = Expression.New(type); Expression<Func<object>> lambdaExp = Expression.Lambda<Func<object>>(newExp, null); Func<object> func = lambdaExp.Compile(); return func; }public static Func<T, object> CreateInstanceDelegate<T>(this Type type)
{ Type paramType = typeof(T); var construtor = type.GetConstructor(new Type[] { paramType }); var param = new ParameterExpression[] { Expression.Parameter(paramType, "arg") };NewExpression newExp = Expression.New(construtor, param);
Expression<Func<T, object>> lambdaExp = Expression.Lambda<Func<T, object>>(newExp, param); Func<T, object> func = lambdaExp.Compile(); return func; } public static Func<T1, T2, object> CreateInstanceDelegate<T1, T2>(this Type type) { var types = new Type[] { typeof(T1), typeof(T2) }; var construtor = type.GetConstructor(types); int i = 0; var param = types.Select(t => Expression.Parameter(t, "arg" + (i++))).ToArray(); NewExpression newExp = Expression.New(construtor, param); Expression<Func<T1, T2, object>> lambdaExp = Expression.Lambda<Func<T1, T2, object>>(newExp, param); Func<T1, T2, object> func = lambdaExp.Compile(); return func; }//以下方法中的Lambda表达式“Expression<Func<object[], object>> ”已经定义参数是object[], 而构造函数的参数却不能自动转化。当使用以下代码作测试,
//以下代码有bug! public static Func<object[], object> CreateInstanceDelegate(this Type type, params object[] args) { var construtor = type.GetConstructor(args.Select(c => c.GetType()).ToArray()); var param = buildParameters(args);NewExpression newExp = Expression.New(construtor, param);
Expression<Func<object[], object>> lambdaExp = Expression.Lambda<Func<object[], object>>(newExp, param); Func<object[], object> func = lambdaExp.Compile(); return func; }static ParameterExpression[] buildParameters(object[] args)
{ int i = 0; List<ParameterExpression> list = new List<ParameterExpression>(); foreach (object arg in args) { list.Add(Expression.Parameter(arg.GetType(), "arg" + (i++))); } return list.ToArray(); }}
}-----------------The End----------------
谢谢大家!
本文出自 Lance Yang