浅谈C#反射机制
反射的定义:审查元数据并收集关于它的类型信息的能力。元数据(编译以后的最基本数据单元)就是一大堆的表,当编译程序集或者模块时,编译器会创建一个类定义表,一个字段定义表,和一个方法定义表等。
System.reflection命名空间包含的几个类,允许你反射(解析)这些元数据表的代码
System.Reflection.Assembly
System.Reflection.MemberInfo
System.Reflection.EventInfo
System.Reflection.FieldInfo
System.Reflection.MethodBase
System.Reflection.ConstructorInfo
System.Reflection.MethodInfo
System.Reflection.PropertyInfo
System.Type
以下是上面几个类的使用方法:
(1)使用Assembly定义和加载程序集,加载在程序集清单中列出模块,以及从此程序集中查找类型并创建该类型的实例。
(2)使用Module了解包含模块的程序集以及模块中的类等,还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。
(3)使用ConstructorInfo了解构造函数的名称、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。使用Type的GetConstructors或 GetConstructor方法来调用特定的构造函数。
(4)使用MethodInfo了解方法的名称、返回类型、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。使用Type的GetMethods或GetMethod方法来调用特定的方法。
(5)使用FiedInfo了解字段的名称、访问修饰符(如public或private)和实现详细信息(如static)等,并获取或设置字段值。
(6)使用EventInfo了解事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等,添加或移除事件处理程序。
(7)使用PropertyInfo了解属性的名称、数据类型、声明类型、反射类型和只读或可写状态等,获取或设置属性值。
(8)使用ParameterInfo了解参数的名称、数据类型、是输入参数还是输出参数,以及参数在方法签名中的位置等。
反射的层次模型:
(注:层次间都是一对多的关系)
反射的作用:
1、可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型
2、应用程序需要在运行时从某个特定的程序集中载入一个特定的类型,以便实现某个任务时可以用到反射。
3、反射主要应用与类库,这些类库需要知道一个类型的定义,以便提供更多的功能。
应用要点:
1、现实应用程序中很少有应用程序需要使用反射类型
2、使用反射动态绑定需要牺牲性能
3、有些元数据信息是不能通过反射获取的
4、某些反射类型是专门为那些clr 开发编译器的开发使用的,所以你要意识到不是所有的反射类型都是适合每个人的
我们下面以一个简单的例子 来演示反射的应用场景
添加一类库 DLL项目ClassLibrary1 编译好的dll放在APP的项目文件夹extend下用于反射
添加一个Class1类 编写遵循项目规则
文件名Class1.cs
源代码
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace ClassLibrary1 8 { 9 public class Class1 10 { 11 public static void TestMain() 12 { 13 Console.WriteLine("ClassLibrary1=>TestMain()"); 14 } 15 } 16 }
添加一个命令行项目ConsoleApp1 并编写调用规则
源代码为
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using System.Reflection; 7 using System.IO; 8 9 namespace ConsoleApp1 10 { 11 class Program 12 { 13 static void Main(string[] args) 14 { 15 string[] Pamerts = new string[] { "class1", "TestMain" };//构造器初始化一个模拟的动态参数第一个为要调用的类,第二个为要调用的该类的方法; 16 FileInfo[] fileInfos = new DirectoryInfo("../.././extend").GetFiles();//设置扩展路径 这是自己模拟的一个反射所需要的场景:定制模块化 17 foreach (FileInfo fileinfo in fileInfos)//遍历扩展路径 18 { 19 Assembly assembly = Assembly.LoadFile(fileinfo.FullName);//加载装配件 20 Type[] types = assembly.GetTypes(); 21 string Class = ""; 22 foreach (Type T in types)//遍历所有装配件 23 { 24 //假设反射对接调用流程为调用参数一类的动态参数参数二方法实现对接 所有定制化模块的编写 都必须按照这个写法 才能被正确调用 25 if (T.FullName.ToString().ToLower().Contains(Pamerts[0]))//判断有无参数一这个类型 26 { 27 Class = T.FullName; 28 break; 29 } 30 } 31 Type type = assembly.GetType(Class);//获得类型 32 object obj = Activator.CreateInstance(type);//创建实例 33 //假设反射对接调用流程为调用参数一类的动态参数参数二方法实现对接 所有定制化模块的编写 都必须按照这个写法 才能被正确调用 34 MethodInfo methodInfo = type.GetMethod(Pamerts[1]);//获得方法 35 methodInfo.Invoke(obj, null); 36 } 37 } 38 } 39 }
运行截图可以看到
APP项目编写反射规则并调用达到交互 反射遵循编写规则 以确保被正确调用
问题来了 反射的意义在于哪里?
我认为吧 其实就是能够通过编程的方式 达到跟APP交互 实现定制化模块,这种场景,实际项目,一般并不会用到.