c#反射实践

来源:互联网 发布:java 条码枪的开发 编辑:程序博客网 时间:2024/05/17 18:03
  1,准备如下的XML文件
  1.   <TestConfig>
  2.     <Test1 Name="aaa" Code="001" />
  3.     <Test2 Name="bbb" Code="002" DefaultText="Wellcome" />
  4.     <Test3 Name="ccc" Code="003" >
  5.       <Item Name="item1" Value="item1" />
  6.       <Item Name="item2" Value="item2" />
  7.     </Test3>
  8.   </TestConfig> 
  2,新建与XML文件中节点名相同的数据类,用来保存配置文件中各个节点的设定值。按照上面XML文件结构,创建以下类:
  1.   using System;
  2.   using System.Collections.Generic;
  3.   using System.Text;
  4. namespace reflection.config
  5. {
  6.     //Test1节点对应的Class
  7.     public class Test1
  8.     {
  9.         //构造器
  10.         public Test1()
  11.         {
  12.             //
  13.         }

  14.         //节点属性-Name
  15.         private string name;
  16.         public string Name
  17.         {
  18.             set { this.name = value; }
  19.             get { return this.name; }
  20.         }

  21.         //节点属性-Code
  22.         private string code;
  23.         public string Code
  24.         {
  25.             set { this.code = value; }
  26.             get { return this.code; }
  27.         }    
  28.     }
  29. }
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;

  4. namespace reflection.config
  5. {
  6.     //Test2节点对应的Class
  7.     public class Test2
  8.     {
  9.         //构造器
  10.         public Test2()
  11.         {
  12.             //
  13.         }
  14.         //节点属性-Name
  15.         private string name;
  16.         public string Name
  17.         {
  18.             set { this.name = value; }
  19.             get { return this.name; }
  20.         }
  21.         //节点属性-Code
  22.         private string code;
  23.         public string Code
  24.         {
  25.             set { this.code = value; }
  26.             get { return this.code; }
  27.         }
  28.         //节点属性-DefaultText;
  29.         private string defaultText;
  30.         public string DefaultText
  31.         {
  32.             set { this.defaultText = value; }
  33.             get { return this.defaultText; }
  34.         }
  35.     }
  36. }

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;

  4. namespace reflection.config
  5. {
  6.     //节点Test3对应的Class
  7.     public class Test3
  8.     {
  9.         //构造器
  10.         public Test3()
  11.         {
  12.             //
  13.         }
  14.         //节点属性-Name
  15.         private string name;
  16.         public string Name
  17.         {
  18.             set { this.name = value; }
  19.             get { return this.name; }
  20.         }
  21.         //节点属性-Code
  22.         private string code;
  23.         public string Code
  24.         {
  25.             set { this.code = value; }
  26.             get { return this.code; }
  27.         }
  28.         //子节点的List-Item
  29.         private List<Item> itemLst;
  30.         public List<Item> ItemLst
  31.         {
  32.             set { this.itemLst = value; }
  33.             get { return this.itemLst; }
  34.         }
  35.     }
  36. }

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;

  4. namespace reflection.config
  5. {
  6.     //节点Item对应的Class
  7.     public class Item
  8.     {
  9.         //构造器
  10.         public Item()
  11.         {
  12.             //
  13.         }
  14.         //节点属性-Name
  15.         private string name;
  16.         public string Name
  17.         {
  18.             set { this.name = value; }
  19.             get { return this.name; }
  20.         }
  21.         //节点属性-Value
  22.         private string value;
  23.         public string Value
  24.         {
  25.             set { this.value = value; }
  26.             get { return this.value; }
  27.         }
  28.     }
  29. }

注意每个类的命名,它们和XML文件中每个节点的名字必须完全相同,否则在使用反射不能对类对象进行数据设定,另外每个类中的属性名也要与文件中节点的属性一致,对于文件中存在子节点的节点,类的创建方法可参照Test3类的编写方法,用范型List<>来保存并列的子节点。

 3,节点的读取,参照下面代码中的ReadConfigInfo()和initNodeObject()方法
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Xml;
  5. using System.Reflection;
  6. namespace reflection.config
  7. {
  8.     //读取Xml文件中的配置信息时的Class
  9.     public class TestConfig
  10.     {
  11.         //xml文件的路径
  12.         private string filePath;
  13.         //构造器
  14.         public TestConfig(string configFilePath)
  15.         {
  16.             //
  17.             filePath = configFilePath;
  18.         }
  19.         //节点属性-Test1
  20.         private Test1 test1;
  21.         public Test1 TestOne
  22.         {
  23.             set { this.test1 = value; }
  24.             get { return this.test1; }
  25.         }
  26.         //节点属性-test2
  27.         private Test2 test2;
  28.         public Test2 TestTwo
  29.         {
  30.             set { this.test2 = value; }
  31.             get { return this.test2; }
  32.         }
  33.         //节点属性-test3
  34.         private Test3 test3;
  35.         public Test3 TestThree
  36.         {
  37.             set { this.test3 = value; }
  38.             get { return this.test3; }
  39.         }
  40.         /// <summary>
  41.         /// 读取XML文件中各节点信息
  42.         /// </summary>
  43.         public void ReadConfigInfo()
  44.         {
  45.             try
  46.             {
  47.                 XmlDocument xmlDoc = new XmlDocument();
  48.                 xmlDoc.Load(filePath);
  49.                 Type selfType = this.GetType();
  50.                 PropertyInfo[] proLst = selfType.GetProperties();
  51.                 foreach (PropertyInfo pro in proLst)
  52.                 {
  53.                     Type proType = pro.PropertyType;
  54.                     string typeName = proType.FullName;
  55.                     //创建节点对象
  56.                     object nodeObj = Activator.CreateInstance(proType);
  57.                     initNodeObject(xmlDoc, nodeObj, 0);
  58.                     pro.SetValue(this, nodeObj, null);
  59.                 }
  60.                 //读取节点Test1的数据
  61.                 /*Test1 t1 = new Test1();
  62.                 initNodeObject(xmlDoc, t1, 0);
  63.                 this.TestOne = t1;
  64.                 //读取节点Test2的数据
  65.                 Test2 t2 = new Test2();
  66.                 initNodeObject(xmlDoc, t2, 0);
  67.                 this.TestTwo = t2;
  68.                 //读取节点Test3的数据
  69.                 Test3 t3 = new Test3();
  70.                 initNodeObject(xmlDoc, t3, 0);
  71.                 this.TestThree = t3;*/
  72.             }
  73.             catch (Exception ex)
  74.             {
  75.                 throw new Exception("从testConfig.xml文件中读取配置信息时,发生错误!"  , ex.InnerException);
  76.             }
  77.         }
  78.         /// <summary>
  79.         /// 把XML文件中节点信息读取到指定的对象中
  80.         /// </summary>
  81.         /// <param name="xmlDoc">XML文件的DOC对象</param>
  82.         /// <param name="nodeObj">保存节点信息的对象</param>
  83.         private void initNodeObject(XmlDocument xmlDoc, Object nodeObj, int nodeIndex)
  84.         {
  85.             string nodeName = nodeObj.GetType().Name;
  86.             //取得XML文件中对应的节点
  87.             XmlNode node = xmlDoc.GetElementsByTagName(nodeName).Item(nodeIndex);
  88.             //取得对象的属性列表
  89.             PropertyInfo[] proLst = nodeObj.GetType().GetProperties();
  90.             foreach (PropertyInfo pro in proLst)
  91.             {
  92.                 if (pro.PropertyType.IsGenericType == false)
  93.                 {
  94.                     string fieldName = pro.Name;
  95.                     //取得配置文件中的设定值
  96.                     string configValue = node.Attributes.GetNamedItem(fieldName).Value;
  97.                     //把取得数据保存到对象的属性中
  98.                     pro.SetValue(nodeObj, configValue, null);
  99.                 }
  100.                 else
  101.                 {
  102.                     Type t = pro.PropertyType;
  103.                     Object olist = Activator.CreateInstance(t);
  104.                     Type[] typeParam = t.GetGenericArguments();
  105.                     MethodInfo addMethod = t.GetMethod("Add");
  106.                     if (typeParam.Length == 1)
  107.                     {
  108.                         Type paramType = typeParam[0];
  109.                         //取得节点名称
  110.                         string childNodeName = paramType.Name;
  111.                         //取得节点列表
  112.                         XmlNodeList nodeLst = xmlDoc.GetElementsByTagName(childNodeName);
  113.                         int count = 0;
  114.                         foreach (XmlElement element in nodeLst)
  115.                         {
  116.                             //创建一个参数类型的实例                      
  117.                             object obj = Activator.CreateInstance(paramType);
  118.                             initNodeObject(xmlDoc, obj, count);
  119.                             count = count + 1;
  120.                             addMethod.Invoke(olist, new object[] { obj });
  121.                         }
  122.                         pro.SetValue(nodeObj, olist, null);
  123.                     }
  124.                 }
  125.             }
  126.         }
  127.     }
  128. }
代码讨论:
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()方法就会完成对应设定处理。
原创粉丝点击