反射Reflection
程序集(Assemblies)与命名空间(namespaces)
命名空间
提供了一个逻辑组织系统,是唯一识别的一套名字,用来避免在命名的冲突。程序集
是.NET程序的部署单元,用于物理包装和配置,像一个类型的容器,可以包含类别(元数据信息)、用于实现这些类型的可执行代码(IL)、资源和对于其他程序集合的链接。
有两种主要种类:应用程序(.exe)和库(.dll),前者有一个主入口而后者没有。关于程序集可参阅这篇
反射定义
审查元数据并收集关于它的类型信息的能力。(关于元数据在特性attribute这一篇有说明,即一类自我描述性数据)
审查这一过程我看到比较好理解的例子应该就是B超了,在不对对象本身做直接干扰的情况下获取对象的基本信息。作用
可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。然后,可以调用类型的方法或访问其字段和属性。
即:- 它允许在运行时查看特性(attribute)信息。
- 它允许审查集合中的各种类型,以及实例化这些类型。
- 它允许延迟(晚)绑定的方法和属性(property)。
- 它允许在运行时(动态)创建新类型,然后使用这些类型执行一些任务。
这里需要重点关注的就是动态。对于C#这类静态类型语言,许多工作可以在编译阶段完成,这样安全性和执行效率都可以得到保证,然而有时候也会出于灵活性设计需要使用晚绑定,在运行阶段进行一些操作,这时候就需要用到反射。
优缺点
优点:- 降低耦合性,提高了程序的灵活性和扩展性,提高自适应能力。
- 它允许程序创建和控制任何类的对象,无需提前硬编码目标类。
缺点: - 性能问题:使用反射基本上是一种解释操作,用于字段和方法接入时要远慢于直接代码。因此反射机制主要应用在对灵活性和拓展性要求很高的系统框架上,普通程序不建议使用。
- 使用反射会模糊程序内部逻辑;程序员希望在源代码中看到程序的逻辑,反射却绕过了源代码的技术,因而会带来维护的问题,反射代码比相应的直接代码更复杂。
具体用法
反射用到的命名空间:
System、System.Reflection
反射用到的主要类:
System.Type
类--通过这个类可以访问任何给定数据类型的信息。
System.Reflection.Assembly
类--它可以用于访问给定程序集的信息,或者把这个程序集加载到程序中。反射的用途:
- 使用
Assembly
定义和加载程序集,加载在程序集清单中列出模块,以及从此程序集中查找类型并创建该类型的实例。 - 使用
Module
了解包含模块的程序集以及模块中的类等,还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。 - 使用
ConstructorInfo
了解构造函数的名称、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。 - 使用
MethodInfo
了解方法的名称、返回类型、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。 - 使用
FiedInfo
了解字段的名称、访问修饰符(如public或private)和实现详细信息(如static)等,并获取或设置字段值。 - 使用
EventInfo
了解事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等,添加或移除事件处理程序。 - 使用
PropertyInfo
了解属性的名称、数据类型、声明类型、反射类型和只读或可写状态等,获取或设置属性值。 - 使用
ParameterInfo
了解参数的名称、数据类型、是输入参数还是输出参数,以及参数在方法签名中的位置等。
- 使用
基本使用方法
调用本地类型中的方法
Type t= Type.GetType(“test”) ; //获取class
MethodInfo method = t.GetMethod(“DebugMsg”); //获取方法信息
object o= Activator.CreateInstance(t); //生成实例
method.Invoke(o, null); //调用方法调用外部dll中的方法
Assembly ass = Assembly.LoadFile(“path/XXX.dll”); //获取dll
Type t= ass.GetType(“test”) ; //获取程序集中对应class
后面同上
关于C#中反射使用更详细的内容可参阅这篇
参考资料:
1. http://www.runoob.com/csharp/csharp-reflection.html
2. https://blog.youkuaiyun.com/qiaoquan3/article/details/51423890
3. 《C#API》