反射在C#是比较常用的一个技术点,vs中的智能提示,我们使用的反编译工具都可以通过反射实现,
首先要了解程序集。在C#中的.dll文件和项目生成的.exe文件都是程序集。
反射就是动态获取程序集中的元数据来操作类型的。
Type类是在反射中经常用到的。
在该段课程中还会介绍几个反射中常用的方法,最后的时候通过反射做一个插件的案例
此章节的所有代码在反射.rar这个文件中。
-----------------------------------------------------------------------------------------------------
什么是程序集? 程序集(Assembly),可以看做是一堆相关类打一个包。
程序集是.net中的概念
。 .net中的dll与exe文件都是程序集。(exe与dll的区别?)
程序集包含:类型元数据(描述在代码中定义的每一类型和成员,二进制形式)、程序集元数据(程序集清单、版本号、名称等)、IL代码(这些都被装在exe或dll中)、资源文件。
每个程序集都有自己的名称、版本等信息。这些信息可以通过AssemblyInfo.cs文件来自己定义。
使用程序集的好处? 程序中只引用必须的程序集,减小程序的尺寸。
程序集可以封装一些代码,只提供必要的访问接口。
如何添加程序集的引用? 添加路径、项目引用
不能循环添加引用
在c#中添加其他语言编写的dll文件的引用
---------------------------------------------------------------------------------------
反射
反射无处不在,我们天天在使用。Vs的智能提示,就是通过反射获取到类的属性、方法等。还有反编译工具也是通过反射实现
反射:就是动态获取程序集中的元数据来操作类型的。
Type类实现反射的一个重要的类,通过它我们可以获取类中的所有信息包括方法、属性等。可以动态调用类的属性、方法。 Type是对类的描述。如何获取Person类中的所有属性?
反射就是直接通过.dll来创建对象,调用成员。
通过类型元数据来获取对象的一些相关信息,并且还可以实例化对象调用方法等,这个就叫做“反射”。
反射让创建对象的方式发生了改变。
编译器的智能提示就是反射的一个应用。
---------------------------------------------------------------------------------------
Type类
Type类的使用
通过类获得Type:Type t = typeof(Person)
通过对象获得类的Type:Type t = p.GetType()
调用Assembly的GetExportedTypes方法可以得到Assembly中定义的所有的public类型。
调用Assembly的GetTypes()方法可以得到Assembly中定义的所有的类型。
调用Assembly的GetType(name)方法可以得到Assembly中定义的全名为name的类型信息。
插件:扩展主程序功能的dll.
---------------------------------------------------------------------------------------
动态创建对象
Activator.CreateInstance(Type t)会动态调用类的无参构造函数创建一个对象,返回值就是创建的对象,如果类没有无参构造函数就会报错。
GetConstructor(参数列表);//这个是找到带参数的构造函数。
Type类的方法:在编写调用插件的程序时,需要做一系列验证。
bool IsAssignableFrom(Type c):(直译:是否可以从c赋值)判断当前的类型的变量是不是可以接受c类型变量的赋值。 typeof(IPlugin).IsAssignableFrom(t)
bool IsInstanceOfType(object o):判断对象o是否是当前类的实例(当前类可以是o的类、父类、接口)
bool IsSubclassOf(Type c):判断当前类是否是类c的子类。
类的事,没有接口的事。
IsAbstract,判断是否为抽象的,含接口
---------------------------------------------------------------------------------------
动态调用成员
MemberInfo类 抽象类,有很多子类,下面讲的类都继承自它,获取程序集成员的相关信息(类型、方法、事件、字段和属性) PropertyInfo 获取属性
主要成员:CanRead、CanWrite、PropertyType属性类型;
SetValue、GetValue:读取值,设置值,第一个参数是实例对象,因为set、get要针对具体实例,最后一个参数null。
pInfo.SetValue(p1, 30, null)
MethodInfo 获取方法
MethodInfo都是和具体对象不相关的,所以需要第一个参数指定要执行的对象。
FieldInfo 获取字段
EventInfo 获取事件
----------------------------------------------------------------------------------------------------
开发插件步骤
创建接口项目,通过接口定义插件怎么去实现
创建插件项目,创建两个插件一个实现汉英翻译功能,一个实现定时关机功能。插件项目要引用接口项目。编译时让插件项目生成在主程序的debug/plugin目录下
创建主程序,主程序要添加对接口项目的引用(不需要对插件引用,对插件的调用是动态的)
主程序中读取Plugin目录下的所有dll文件,加载成Assembly Ass.GetExportedTypes读取Assembly中的公共类型
IsAssignableFrom判断对象能否委派给某类型,是否是类并且不能使抽象类
动态添加菜单