1. 反射是什么
1.1 概述
反射是指程序在运行状态中,动态获取程序的信息以及动态调用任意对象的方法的功能。
2. 反射原理
2.1 C#编译过程
DLL/EXE(程序集) : DLL/EXE可以看作是给一堆相关类打一个包,以及一些资源文件的逻辑组合。在 .NET 中,dll与exe文件都是程序集。程序集包含:资源文件,类型元数据,IL代码。
metadate: 元数据数据清单,记录了exe/dll中包含了哪些东西,是一个描述,描述在代码中定义的每一类型和成员,二进制形式。
IL:中间语言,编译器把高级语言编译后得到的C#中最真实的语言状态。
2.2 原理解析
反射技术就是运用System.Reflection,.Net框架提供的帮助类库,可以读取并且使用dll/exe(程序集)的metadate去动态的创建对象,调用成员。
3. 使用反射
3.1 反射用到的命名空间
System.Reflection
//引用type类 --通过这个类可以访问任何给定数据类型的信息
System.Type
//引用 Assembly类 --它可以使用于访问给定程序集的信息,或者把这个程序集加载到程序中。
System.Reflection.Assembly
System.Type类对于反射起着核心的作用。但它是一个抽象的基类,Type有与每种数据类型对应的派生类,我们使用这个派生类的对象的方法、字段、属性来查找有关该类型的所有信息。
3.2 应用示例(简单展示)
- 动态读取dll
using System;
using System.Reflection;
public class Example
{
static void Main()
{
//LoadFrom : dll全名称, 需要后缀
Assembly assembly = Assembly.LoadFrom("Bussiness.DB.SqlServer.dll");
//loadFile: 全路径, 需要后缀
Assembly assembly1 = Assembly.LoadFile(@"//dll文件全路径");
//Load: dll名称不需要后缀
Assembly assembly2 = Assembly.Load("Bussiness.DB.SqlServer")
}
}
- 反射动态创建对象
//获取某一个具体的类,参数需要是类的全名称
Type type = assmbly.GetType("Business.DB.SqlServer.SqlServerHelper")
//直接传类型创建实例
dynamic dInstance = Activator.CreateInstance(type);
//类型转换
SqlServerHelper helper = dInstance as SqlServerHelper;
//调用方法
helper.Query();
- 反射为字段属性赋值取值
Type type = assmbly.GetType("Business.DB.SqlServer.SqlServerHelper")
dynamic dInstance = Activator.CreateInstance(type);
//遍历类的属性 因为是反射所以没办法明指点具体属性
foreach(var prop in type.GetProperties())
{
if (prop.Name.Equals("Id"))
{
//赋值时, 要将实例和value一起传进去
prop.SetValue(dInstance , 134);
}
else if (prop.Name.Equals("Name"))
{
prop.SetValue(dInstance , "不要学编程");
}
else if (prop.Name.Equals("Age"))
{
prop.SetValue(dInstance , 25);
}
}
//取值
foreach(var prop in type.GetProperties())
{
Console.WriteLine($"people.{prop.Name}={prop.GetValue(pObject)}");
}
- 使用反射访问特性
3.3 反射的应用场景
- IOC容器:反射+ 配置文件+ 工厂
- MVC框架:反射调用类型方法
- ORM:反射+泛型+Ado.Net
- AOP:在方法的前面后面添加处理内容,添加通用逻辑
4. 反射的优缺点
4.1 优点:
-
提高了程序的扩展性和灵活性,反射依赖于配置文件,可以做到不修改代码而改变程序的功能,避免将程序写死到代码里。
-
降低耦合度,断开了对普通类的依赖,提高自适应能力。
-
允许动态的创建和使用任何对象,无需提前硬编码目标对象。
4.2 缺点:
-
性能较低,使用反射基本上是一种解释操作,用于字段和方法接入时要远慢于直接代码(直接编码是最快的)。因此反射机制主要应用在对灵活性和扩展性要求很高的系统框架上,普通程序不建议使用。
-
可读性较低,使用反射会模糊程序内内部逻辑:程序员希望在源代码中看到程序的逻辑,反射等绕过了源代码的技术,因而会带来维护问题。反射代码比相应的直接代码更复杂。
-
内部暴露,破坏封装,由于反射允许代码执行一些在正常情况下不被允许的操作(比如访问私有的属性和方法),所以使用反射可能会导致意料之外的副作用--代码有功能上的错误,降低可移植性。反射代码破坏了抽象性,因此当平台发生改变的时候,代码的行为就有可能也随着变化。
4.3 反射是否真的会让程序性能降低?
-
反射大概比直接调用慢50~100倍,但是需要在执行100万遍的时候才会有所感觉
-
判断一个函数的性能,需要把这个函数执行100万遍甚至1000万遍
-
如果只是偶尔调用一下反射,请忘记反射带来的性能影响
-
如果需要大量调用反射,请考虑反射 + 缓存。
编程思想才是限制程序性能的最主要的因素。