1,准备如下的XML文件
- <TestConfig>
- <Test1 Name="aaa" Code="001" />
- <Test2 Name="bbb" Code="002" DefaultText="Wellcome" />
- <Test3 Name="ccc" Code="003" >
- <Item Name="item1" Value="item1" />
- <Item Name="item2" Value="item2" />
- </Test3>
- </TestConfig>
2,新建与XML文件中节点名相同的数据类,用来保存配置文件中各个节点的设定值。按照上面XML文件结构,创建以下类:
注意每个类的命名,它们和XML文件中每个节点的名字必须完全相同,否则在使用反射不能对类对象进行数据设定,另外每个类中的属性名也要与文件中节点的属性一致,对于文件中存在子节点的节点,类的创建方法可参照Test3类的编写方法,用范型List<>来保存并列的子节点。
3,节点的读取,参照下面代码中的ReadConfigInfo()和initNodeObject()方法
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Xml;
- using System.Reflection;
- namespace reflection.config
- {
-
- public class TestConfig
- {
-
- private string filePath;
-
- public TestConfig(string configFilePath)
- {
-
- filePath = configFilePath;
- }
-
- private Test1 test1;
- public Test1 TestOne
- {
- set { this.test1 = value; }
- get { return this.test1; }
- }
-
- private Test2 test2;
- public Test2 TestTwo
- {
- set { this.test2 = value; }
- get { return this.test2; }
- }
-
- private Test3 test3;
- public Test3 TestThree
- {
- set { this.test3 = value; }
- get { return this.test3; }
- }
-
-
-
- public void ReadConfigInfo()
- {
- try
- {
- XmlDocument xmlDoc = new XmlDocument();
- xmlDoc.Load(filePath);
- Type selfType = this.GetType();
- PropertyInfo[] proLst = selfType.GetProperties();
- foreach (PropertyInfo pro in proLst)
- {
- Type proType = pro.PropertyType;
- string typeName = proType.FullName;
-
- object nodeObj = Activator.CreateInstance(proType);
- initNodeObject(xmlDoc, nodeObj, 0);
- pro.SetValue(this, nodeObj, null);
- }
-
-
- }
- catch (Exception ex)
- {
- throw new Exception("从testConfig.xml文件中读取配置信息时,发生错误!" , ex.InnerException);
- }
- }
-
-
-
-
-
- private void initNodeObject(XmlDocument xmlDoc, Object nodeObj, int nodeIndex)
- {
- string nodeName = nodeObj.GetType().Name;
-
- XmlNode node = xmlDoc.GetElementsByTagName(nodeName).Item(nodeIndex);
-
- PropertyInfo[] proLst = nodeObj.GetType().GetProperties();
- foreach (PropertyInfo pro in proLst)
- {
- if (pro.PropertyType.IsGenericType == false)
- {
- string fieldName = pro.Name;
-
- string configValue = node.Attributes.GetNamedItem(fieldName).Value;
-
- pro.SetValue(nodeObj, configValue, null);
- }
- else
- {
- Type t = pro.PropertyType;
- Object olist = Activator.CreateInstance(t);
- Type[] typeParam = t.GetGenericArguments();
- MethodInfo addMethod = t.GetMethod("Add");
- if (typeParam.Length == 1)
- {
- Type paramType = typeParam[0];
-
- string childNodeName = paramType.Name;
-
- XmlNodeList nodeLst = xmlDoc.GetElementsByTagName(childNodeName);
- int count = 0;
- foreach (XmlElement element in nodeLst)
- {
-
- object obj = Activator.CreateInstance(paramType);
- initNodeObject(xmlDoc, obj, count);
- count = count + 1;
- addMethod.Invoke(olist, new object[] { obj });
- }
- pro.SetValue(nodeObj, olist, null);
- }
- }
- }
- }
- }
- }
代码讨论:
1,在上记代码中统一使用了类属性,即每个属性带有get和set方法,当然也可以使用类字段。
2,在ReadConfigInfo()和initNodeObject()方法中都用到反射。
在ReadConfigInfo()中使用如下语句取得需要保存Xml文件节点配置信息的类对象,
Type selfType = this.GetType();
PropertyInfo[] proLst = selfType.GetProperties(); //如果使用类字段, 应该使用GetFileds()方法,取得FieldInfo类型数组,
以下语句是用来实例化对象的,这里看不到new操作符了哦
Type proType = pro.PropertyType;
string typeName = proType.FullName;
//创建节点对象
object nodeObj = Activator.CreateInstance(proType);
//把结果保存到相应的属性中。
pro.SetValue(this, nodeObj, null);
在initNodeObject()方法中,应用方法与上记说明基本相同,不同的是这是一个第归方法,用于取得含有子节点Xml节点中的数据。对于含有子节点的Xml节点,使用以下语句判断对应的类对象中保存字节点的属性
if (pro.PropertyType.IsGenericType == false)
{
//当前节点属性值设定
}
else
{
//取得保存子节点数据的对象类型
Type t = pro.PropertyType;
//创建对象实例
Object olist = Activator.CreateInstance(t);
//取得范型对象可以保存的数据类型
Type[] typeParam = t.GetGenericArguments();
//取得向List中添加数据的方法
MethodInfo addMethod = t.GetMethod("Add");
//其他处理可参照代码中的注释。
}
综上所述,读取XML文件配置数据的方法就写完了,以后,如果要在XML文件中追加配置信息,只需要在工程中添加对应的节点类,在TestConfig类中追加对应的类的属性就可以了。ReadConfigInfo()和initNodeObject()方法就会完成对应设定处理。