博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C#教程之自己动手写映射第三节[反射]
阅读量:6586 次
发布时间:2019-06-24

本文共 8190 字,大约阅读时间需要 27 分钟。

一、什么是反射

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

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

  反射的名称空间:System.Reflection,具体参考

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

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

  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.Model16 {17     /// 18     /// 员工类19     /// 20     public class Employee21     {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         /// 29         /// 测试方法30         /// 31         /// 
32 public string Method()33 {34 return this.ID.ToString();35 }36 }37 }

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

1 
2
3
4
5
6
7
8 9 10 11 /*12 *13 * 创建人:李林峰14 * 15 * 时 间:2012-7-2316 *17 * 描 述:常量类18 *19 */20 21 using System.Configuration;22 23 namespace CSharp.Reflection24 {25 class Constant26 {27 /// 28 /// 程序集名称29 /// 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.Reflection15 {16     class Program17     {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 
2
3
4
12
13
14 15 16 /*17 *18 * 创建人:李林峰19 * 20 * 时 间:2012-7-2321 *22 * 描 述:常量类23 *24 */25 26 using System.Configuration;27 28 namespace CSharp.Dynamic29 {30 class Constant31 {32 /// 33 /// 程序集名称34 /// 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.Dynamic17 {18     class Program19     {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:支持编程语言的源代码的生成和编译进行管理。具体参考:

  Microsoft.CSharp:编译和生成代码,名称空间下只有一个类CSharpCodeProvider。具体参考:

  设置属性: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.Object10 将设置其属性值的对象。11 12 value13 类型:System.Object14 此属性的新值。15 16 index17 类型: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 index12 类型:System.Object[]13 索引化属性的可选索引值。 对于非索引化属性,该值应为 null。 14 15 返回值16 类型:System.Object17 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[] parameters12  类型:System.Object[]13  参数数组,如果参数为空,该值应为 null。 14  15  返回值16  类型:System.Object17  obj 参数指定的对象的属性值。

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

  运行效果如下图所示:

 

 

四、总结

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

五、源码下载

  

六、版权

  转载请注明出处:

 

你可能感兴趣的文章
JMeter5.0 边界提取器使用
查看>>
Windows Azure 上的 Symfony,适用于 PHP 开发者的强大组合
查看>>
堆和栈的区别 (转贴)
查看>>
通过包名获取该包下的所有类
查看>>
【JavaScript学习笔记】画图
查看>>
Linux写时拷贝技术(copy-on-write)
查看>>
opencv视频读取问题
查看>>
java Iterator Fail-fast机制
查看>>
Java堆外内存之五:堆外内存管理类ByteBuffer
查看>>
HTML5 input placeholder 颜色修改
查看>>
TJ/T808 终端通讯协议设计与实现(码农本色)
查看>>
分布式搜索引擎Elasticsearch的查询与过滤
查看>>
SolidEdge 工程图中如何给零件添加纹理或贴图
查看>>
【Java面试题】14 super.getClass()方法调用
查看>>
六种流行的语言---C、C++、python、Java、php、C#比较[转]
查看>>
AP INVOICES IMPORT API(NOT request)
查看>>
怎样面试程序猿
查看>>
Redhat6.5安装DB2 Express-C版本
查看>>
php的http数据传输get/post...
查看>>
【剑指Offer面试题】 九度OJ1368:二叉树中和为某一值的路径
查看>>