• C#教程之自己动手写映射第三节[反射]


    一、什么是反射

      MSND:反射提供了封装程序集、模块和类型的对象(Type 类型)。可以使用反射动态创建类型的实例,将类型绑定到现有对象,或从现有对象获取类型并调用其方法或访问其字段和属性。如果代码中使用了属性,可以利用反射对它们进行访问。

      实用概念:反射是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为反射。

      反射的名称空间:System.Reflection,具体参考 http://msdn.microsoft.com/zh-cn/library/system.reflection.aspx

    二、利用反射动态创建类的实例

      前置条件:我们创建两个项目来展示反射的简单应用

    1. CSharp.Model:类库,Employee.cs,我们要反射的测试实体类
    2. CSharp.Reflection:控制台应用程序项目,Program.cs为主程序类,App.config配置文件,配置我们要反射的程序集的名称,Constant.cs用于调用配置文件的常量类。

      CSharp.Model.Employee代码如下:

     1 /*
     2  *
     3  * 创建人:李林峰
     4  * 
     5  * 时  间:2012-7-23
     6  *
     7  * 描  述:反射类的实例
     8  *
     9  */
    10 
    11 using System;
    12 using System.Collections.Generic;
    13 using System.Text;
    14 
    15 namespace CSharp.Model
    16 {
    17     /// <summary>
    18     /// 员工类
    19     /// </summary>
    20     public class Employee
    21     {
    22         public int ID { get; set; }             //编号
    23         public string Name { get; set; }        //姓名
    24         public string Password { get; set; }    //密码
    25         public string Department { get; set; }  //部门
    26         public string Position { get; set; }    //职位
    27 
    28         /// <summary>
    29         /// 测试方法
    30         /// </summary>
    31         /// <returns></returns>
    32         public string Method()
    33         {
    34             return this.ID.ToString();
    35         }
    36     }
    37 }

      CSharp.Reflection的配置文件与常量类代码如下:

     1 <?xml version="1.0" encoding="utf-8" ?>
     2 <configuration>
     3   <appSettings>
     4     <!--程序集名称-->
     5     <add key="AssemblyName" value="CSharp.Model"></add>
     6   </appSettings>
     7 </configuration>
     8 
     9 
    10 
    11 /*
    12  *
    13  * 创建人:李林峰
    14  * 
    15  * 时  间:2012-7-23
    16  *
    17  * 描  述:常量类
    18  *
    19  */
    20 
    21 using System.Configuration;
    22 
    23 namespace CSharp.Reflection
    24 {
    25     class Constant
    26     {
    27         /// <summary>
    28         /// 程序集名称
    29         /// </summary>
    30         public static string ASSEMBLYNAME = ConfigurationManager.AppSettings["AssemblyName"];
    31     }
    32 }

      CSharp.Reflection的主程序类代码如下:

     1 /*
     2  *
     3  * 创建人:李林峰
     4  * 
     5  * 时  间:2012-7-23
     6  *
     7  * 描  述:应用程序入口
     8  *
     9  */
    10 
    11 using System.Reflection;//反射的名称空间
    12 using CSharp.Model;     //实体名称空间
    13 
    14 namespace CSharp.Reflection
    15 {
    16     class Program
    17     {
    18         static void Main(string[] args)
    19         {
    20             Employee employee = (Employee)Assembly.Load(Constant.ASSEMBLYNAME).CreateInstance("CSharp.Model.Employee");
    21             employee.ID = 1;
    22             employee.Name = "李林峰";
    23             employee.Department = "技术";
    24             employee.Position = "程序员";
    25             System.Console.WriteLine(employee.Name);
    26             System.Console.WriteLine(employee.Department);
    27             System.Console.WriteLine(employee.Position);
    28             System.Console.WriteLine(employee.Method());
    29 
    30             System.Console.WriteLine("---------------------------------");
    31 
    32             Employee employeeNew = (Employee)Assembly.LoadFile(@"E:\公司内网\HZYT.Test\06 C#映射教程\ClassThree\CSharp.Reflection\bin\Debug\CSharp.Model.dll").CreateInstance("CSharp.Model.Employee");
    33             employee.ID = 2;
    34             employeeNew.Name = "李林峰";
    35             employeeNew.Department = "技术";
    36             employeeNew.Position = "程序员";
    37             System.Console.WriteLine(employeeNew.Name);
    38             System.Console.WriteLine(employeeNew.Department);
    39             System.Console.WriteLine(employeeNew.Position);
    40             System.Console.WriteLine(employee.Method());
    41         }
    42     }
    43 }

      通过上面的示例可以看出,平时我们在创建对象的时候是通过 Employee employee = new Employee(); 来创建。而应用了反射后,我们通过方法System.Reflection.Assembly.Load("程序集名称").CreateInstance("类型名称");在运行时动态的创建类的实例。

      上面的实例中我用了两个方法,主要是强调下反射中Load的是程序集,如上示例employee的实例创建,实际上反射的是已经被我们编译好的,存在于bin目录下的CSharp.Model.dll。而employeeNew我们用的方法是LoadFile,其实原理是一样的,只不过这个方法我们提供的是物理地址。

      CreateInstance("类型名称")中的"类型名称"一定要为类的全名,即:"名称空间"+"类名"。

      反射出来的为Object对象,我们在使用的时候要进行类型转换,如上例所示(Employee)Assembly.Load......

      运行效果如下图所示:

    三、利用反射动创建类

      动态创建类:通过字符串描述类的结构,然后由.net编辑器编辑成类文件,如有必要还可以编辑成.dll的一个动态使用类的过程。

      首先我们先进行类的描述,在很多框架中XML是类描述的主要文件类型,这里我们也不例外,为了简单起见我在本例中用了App.config文件来描述类。

      前置条件:

    1. CSharp.Dynamic:控制台应用程序,Program.cs为主程序类,App.config用于描述类的结构,Constant.cs读取配置文件的常量类。

      CSharp.Dynamic的配置文件与常量类代码如下:

     1 <?xml version="1.0" encoding="utf-8" ?>
     2 <configuration>
     3   <appSettings>
     4     <add key="ClassDefined" value="namespace CSharp.Dynamic{
     5                                    public class Employee{
     6                                       public int ID { get; set; } 
     7                                       public string Name { get; set; }
     8                                       public string Department { get; set; }
     9                                       public string Position { get; set; }
    10                                       public string Method(string parm){return parm+this.ID.ToString();}
    11                                    }}"/>
    12   </appSettings>
    13 </configuration>
    14 
    15 
    16 /*
    17  *
    18  * 创建人:李林峰
    19  * 
    20  * 时  间:2012-7-23
    21  *
    22  * 描  述:常量类
    23  *
    24  */
    25 
    26 using System.Configuration;
    27 
    28 namespace CSharp.Dynamic
    29 {
    30     class Constant
    31     {
    32         /// <summary>
    33         /// 程序集名称
    34         /// </summary>
    35         public static string CLASSDEFINED = ConfigurationManager.AppSettings["ClassDefined"];
    36     }
    37 }

      CSharp.Dynamic的主程序类代码如下:

     1 /*
     2  *
     3  * 创建人:李林峰
     4  * 
     5  * 时  间:2012-7-23
     6  *
     7  * 描  述:利用反射动创建类实例
     8  *
     9  */
    10 
    11 using System;
    12 using System.CodeDom.Compiler;   
    13 using Microsoft.CSharp;            
    14 using System.Reflection;            
    15 
    16 namespace CSharp.Dynamic
    17 {
    18     class Program
    19     {
    20         static void Main(string[] args)
    21         {
    22             //在App.Config中读取类的定义字符串
    23             string ClassDefined = Constant.CLASSDEFINED;
    24             //创建代码编译器
    25             CSharpCodeProvider codeProvider = new CSharpCodeProvider();
    26             //设置编译参数   
    27             CompilerParameters paras = new CompilerParameters();
    28             //设置在内存中生成输出。
    29             paras.GenerateInMemory = true;
    30             //编译代码  
    31             CompilerResults result = codeProvider.CompileAssemblyFromSource(paras, ClassDefined);
    32             //获取编译后的程序集
    33             Assembly assembly = result.CompiledAssembly;
    34             //获取反射出来的对象
    35             Object dynamicClass = assembly.CreateInstance("CSharp.Dynamic.Employee");
    36             //获取员工实例的类型
    37             Type employee = dynamicClass.GetType();
    38             //设置属性
    39             employee.GetProperty("ID").SetValue(dynamicClass, 1, null);
    40             employee.GetProperty("Name").SetValue(dynamicClass, "李林峰", null);
    41             employee.GetProperty("Department").SetValue(dynamicClass, "技术部", null);
    42             employee.GetProperty("Position").SetValue(dynamicClass, "程序员", null);
    43             //读取属性
    44             string Name = employee.GetProperty("Name").GetValue(dynamicClass, null).ToString();
    45             string Department = employee.GetProperty("Department").GetValue(dynamicClass, null).ToString();
    46             string Position = employee.GetProperty("Position").GetValue(dynamicClass, null).ToString();
    47             //执行方法
    48             string ParmAndID = employee.GetMethod("Method").Invoke(dynamicClass, new object[] { "员工编号:" }).ToString();
    49             //输出
    50             Console.WriteLine(Name);
    51             Console.WriteLine(Department);
    52             Console.WriteLine(Position);
    53             Console.WriteLine(ParmAndID);
    54         }
    55     }
    56 }

      我们在App.config中定义了Employee类的结构,通过string ClassDefined = Constant.CLASSDEFINED;把字符串引用到程序中,并进行一系统的处理。

      反射创建类的步骤如下:

    1. 用字符串定义类的结构。
    2. 创建代码编译器并编译。
    3. 获取编译后的程序集并反射出类的对象和类型。
    4. 属性、方法、事件等......赋值。
    5. 使用属性、方法、事件等......。
    6. 如果编译参数设置成内存输入[paras.GenerateInMemory = true;],则由.net 内存回收托管,否则在Temp[C:\Users\Administrator\AppData\Local\Temp]文件夹中产生临时文件"随机字符.dll",每运行一次该程序都将会产生一个新的DLL。

      在上例中,除了导入了System.Reflection名称空间外还导入了System.CodeDom.Compiler与Microsoft.CSharp。

      System.CodeDom.Compiler:支持编程语言的源代码的生成和编译进行管理。具体参考:http://msdn.microsoft.com/zh-cn/library/z6b99ydt

      Microsoft.CSharp:编译和生成代码,名称空间下只有一个类CSharpCodeProvider。具体参考:http://msdn.microsoft.com/zh-cn/library/microsoft.csharp.aspx

      设置属性:employee.GetProperty("ID").SetValue(dynamicClass, 1, null);

     1 public virtual void SetValue(
     2     Object obj,
     3     Object value,
     4     Object[] index
     5 )
     6 
     7 参数
     8 obj
     9 类型:System.Object
    10 将设置其属性值的对象。
    11 
    12 value
    13 类型:System.Object
    14 此属性的新值。
    15 
    16 index
    17 类型:System.Object[]
    18 索引化属性的可选索引值。 对于非索引化属性,该值应为 null

      读取属性:employee.GetProperty("Name").GetValue(dynamicClass, null);

     1 public virtual Object GetValue(
     2     Object obj,
     3     Object[] index
     4 )
     5 
     6 参数
     7 obj
     8 类型:System.Object
     9 将返回其属性值的对象。
    10 
    11 index
    12 类型:System.Object[]
    13 索引化属性的可选索引值。 对于非索引化属性,该值应为 null14 
    15 返回值
    16 类型:System.Object
    17 obj 参数指定的对象的属性值。

      执行方法:employee.GetMethod("Method").Invoke(dynamicClass, new object[] { "员工编号:" });

     1 public Object Invoke(
     2     Object obj,
     3     Object[] parameters
     4 )
     5 
     6  参数
     7  obj
     8  类型:System.Object
     9  实体对象。
    10  
    11 Object[] parameters
    12  类型:System.Object[]
    13  参数数组,如果参数为空,该值应为 null14  
    15  返回值
    16  类型:System.Object
    17  obj 参数指定的对象的属性值。

      上面的三个方法中的employee为类型,dynamicClass对象的实例。

      运行效果如下图所示:

    四、总结

       反射在实际应用中还是比较广泛的,从设计模式的典型"抽象工厂模式"到我们平时应用到的"框架",都会用到反射,其原理大多是动态创建类,如:根据数据库的字段动态生成类,执行些方法等等。为了在介绍"C#教程之自己动手写映射"的课程,这里我只对反射常用的方法进行了讲解,如果感兴趣的话可查看MSND继续研究。

    五、源码下载

      06CSharp映射教程_03.rar

    六、版权

      转载请注明出处:http://www.cnblogs.com/iamlilinfeng

  • 相关阅读:
    Linux 之dhcp服务搭建
    常用网络指令
    图解:光缆、终端盒、尾纤的作用和接法
    Excel2007给表格设置成只读加密属性 让他人无法修改
    CentOS 安裝 VMware Workstation / VMware Player
    Linux 命令之 grep
    iOS开发UI篇—从代码的逐步优化看MVC
    iOS开发UI篇—字典转模型
    iOS开发UI篇—九宫格坐标计算
    iOS开发UI篇—懒加载
  • 原文地址:https://www.cnblogs.com/iamlilinfeng/p/2605512.html
Copyright © 2020-2023  润新知