利用反射进行xml文件配置参数管理
引言:
系统越来越大,配置文件越来越多。之前一直采用直接从xml文件里读取的方式:
XmlDocument doc = new XmlDocument(); string fileName = Application.StartupPath+@"\Settings\SystemConfig.xml"; doc.Load(fileName); XmlNode SystemIDXml = doc.SelectSingleNode(@"ROOT/SystemID"); return SystemIDXml .InnerText.Trim();
使用时不方便,还容易因写错节点名称,形成bug。
并且每次系统升级,都还得写语句对原有配置文件节点进行升级,很是痛苦不堪。
前几天终于忍受不了,琢磨了一下,遂利用反射,完成配置文件的管理。
直接上码。
正文:
1、首先声明该配置文件类,叶子节点需采用属性形式。下面是示例.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Xml; using System.Reflection; namespace Settings { public class ManagementSystemConfig { public class PageTime { public DateTime? BeginTime { get; set; } public DateTime? EndTime { get; set; } public int? DayGap { get; set; } } public PageTime BillPageTime = new PageTime(); public string DepartmentID { get; set; } public class PrintSetting { public PrintSetting() { //设置初始值 IsCombine = true; } public bool IsCombine { get; set; } public string TempletName { get; set; } public string PrinterName { get; set; } public string PaperName { get; set; } public string Orientation { get; set; } public double? Left { get; set; } public double? Right { get; set; } public double? Top { get; set; } public double? Bottom { get; set; } } public PrintSetting EnterPrintSetting = new PrintSetting(); public PrintSetting OutPrintSetting = new PrintSetting(); public void getProperties(string fullPathName) { XmlDocument xml = new XmlDocument(); xml.Load(fullPathName); XmlNodeList xmList = xml.SelectSingleNode("Root").ChildNodes; Common.XmlSetting.MyXmlByReflection.GetPropertiesValue(this, xml.SelectSingleNode("Root"), ""); } public void checkXml(string fullPathName) { XmlDocument xml = new XmlDocument(); if (!System.IO.File.Exists(fullPathName)) { XmlDeclaration dec = xml.CreateXmlDeclaration("1.0", "utf-8", null); xml.AppendChild(dec); XmlElement root = xml.CreateElement("Root"); xml.AppendChild(root); xml.Save(fullPathName); } xml.Load(fullPathName); bool isEdit = false; Common.XmlSetting.MyXmlByReflection.CheckXmlName(this, xml.SelectSingleNode("Root"), xml, ref isEdit); if (isEdit) xml.Save(fullPathName); } public void updateXml(string fullPathName) { XmlDocument xml = new XmlDocument(); xml.Load(fullPathName); Common.XmlSetting.MyXmlByReflection.UpdateXmlValue(this, xml.SelectSingleNode("Root")); xml.Save(fullPathName); } } }
2、关键函数
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Xml; using System.Reflection; namespace Common.XmlSetting { public static class MyXmlByReflection { /// <summary> /// 获取值 /// </summary> /// <param name="obj"></param> /// <param name="xln"></param> /// <param name="propertyNameParent"></param> public static void GetPropertiesValue(object obj, XmlNode xln, string propertyNameParent) { string propertyNameChildren = ""; for (int j = 0; j < xln.ChildNodes.Count; j++) { propertyNameChildren = xln.ChildNodes[j].LocalName; XmlNodeList xlnList = xln.ChildNodes[j].ChildNodes; if (xlnList.Count <= 1) { if (propertyNameChildren != "") { //配置文件类中有无此属性 if (obj.GetType().GetProperty(propertyNameChildren) != null) { //该属性是否可为空 如:int? //赋值 if (Common.MyReg.IsNullableType(obj.GetType().GetProperty(propertyNameChildren).PropertyType) && xln.ChildNodes[j].InnerText.Trim().Length == 0) { obj.GetType().GetProperty(propertyNameChildren).SetValue(obj, null, null); } else obj.GetType().GetProperty(propertyNameChildren).SetValue(obj, Convert.ChangeType(xln.ChildNodes[j].InnerText.Trim(), (Nullable.GetUnderlyingType(obj.GetType().GetProperty(propertyNameChildren).PropertyType) ?? obj.GetType().GetProperty(propertyNameChildren).PropertyType)), null); } } } else { //配置文件类中的子树 if (obj.GetType().GetField(propertyNameChildren) != null) { object o = obj.GetType().InvokeMember(propertyNameChildren, BindingFlags.GetField, null, obj, null); GetPropertiesValue(o, xln.ChildNodes[j], propertyNameChildren); } } } } /// <summary> /// 根据配置文件类初始化配置文件 /// </summary> /// <param name="obj"></param> /// <param name="xn"></param> /// <param name="xml"></param> /// <param name="isEdit"></param> public static void CheckXmlName(object obj, XmlNode xn, XmlDocument xml, ref bool isEdit) { foreach (PropertyInfo pi in obj.GetType().GetProperties()) { XmlNode xltemp = xn.SelectSingleNode(pi.Name); //有无此节点 if (xltemp == null) { XmlNode xe = xml.CreateNode(XmlNodeType.Element, pi.Name, null); //有无初始值 if (pi.GetValue(obj, null) != null && xe.InnerText.Trim().Length == 0) xe.InnerText = pi.GetValue(obj, null).ToString(); xn.AppendChild(xe); isEdit = true; } else { //若有初始值,并且节点值为空,赋值 if (pi.GetValue(obj, null) != null && xltemp.InnerText.Trim().Length == 0) xltemp.InnerText = pi.GetValue(obj, null).ToString(); isEdit = true; } } //检索子节点 foreach (FieldInfo fi in obj.GetType().GetFields()) { XmlNode xltemp = xn.SelectSingleNode(fi.Name); if (xltemp == null) { XmlNode xe = xml.CreateNode(XmlNodeType.Element, fi.Name, null); xn.AppendChild(xe); isEdit = true; } object o = obj.GetType().InvokeMember(fi.Name, BindingFlags.GetField, null, obj, null); CheckXmlName(o, xn.SelectSingleNode(fi.Name), xml, ref isEdit); } } /// <summary> /// 更新配置文件 /// </summary> /// <param name="obj"></param> /// <param name="xn"></param> public static void UpdateXmlValue(object obj, XmlNode xn) { foreach (PropertyInfo pi in obj.GetType().GetProperties()) { XmlNode xltemp = xn.SelectSingleNode(pi.Name); object o = obj.GetType().InvokeMember(pi.Name, BindingFlags.GetProperty, null, obj, null); if (o != null) xltemp.InnerText = pi.GetValue(obj, null).ToString(); else xltemp.InnerText = string.Empty; } foreach (FieldInfo fi in obj.GetType().GetFields()) { object o = obj.GetType().InvokeMember(fi.Name, BindingFlags.GetField, null, obj, null); UpdateXmlValue(o, xn.SelectSingleNode(fi.Name)); } } } }
using System; using System.Collections.Generic; using System.Text; using System.Diagnostics; using System.Runtime.InteropServices; namespace Common { public class MyReg { //type可空否 public static bool IsNullableType(Type theType) { return (theType.IsGenericType && theType. GetGenericTypeDefinition().Equals (typeof(Nullable<>))); } } }
使用方法
先在程序里声明该静态对象,及其路径、名称。
public static class PublicValue { public static Settings.ManagementSystemConfig SMSC = new Settings.ManagementSystemConfig(); public static string SMSC_FullPath = System.Windows.Forms.Application.StartupPath + @"\Settings\SystemConfig.xml"; }
程序启动时初始化
static class Program { /// <summary> /// 应用程序的主入口点。 /// </summary> [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); PublicValue.SMSC = new Settings.ManagementSystemConfig(); //更新配置文件 PublicValue.SMSC.checkXml(PublicValue.SMSC_FullPath); //获取值 PublicValue.SMSC.getProperties(PublicValue.SMSC_FullPath); Application.Run(new MainForm()); } }
程序里使用
Settings.ManagementSystemConfig t_SMSC = new Settings.ManagementSystemConfig();
t_SMSC.getProperties(PublicValue.SMSC_FullPath);
foreach (string fPrinterName in PrinterSettings.InstalledPrinters) { //使用时可直接利用vs的智能感知! if (t_SMSC.OutPrintSetting.PrinterName == fPrinterName) { System.Drawing.Printing.PrintDocument pd = new System.Drawing.Printing.PrintDocument(); pd.PrinterSettings.PrinterName = fPrinterName;
程序里更新
Settings.ManagementSystemConfig t_SMSC = new Settings.ManagementSystemConfig();
t_SMSC.getProperties(PublicValue.SMSC_FullPath);
t_SMSC.EnterPrintSetting.PrinterName = this.textBoxPrintName.Text.Trim();
PublicValue.SMSC = t_SMSC;
PublicValue.SMSC.updateXml(PublicValue.SMSC_FullPath);
MessageBox.Show("保存成功!");
over
看来还是例子实在: