反射笔记
反射必须首先引用 System.Reflection; 这个命名空间
反射的流程,加载dll,用typeof 获取类型,然后创建实例,然后再用invoke 实例的方法
加载dll的方式有三种,如下图
Assembly.Load //dll名称无后缀 从当前目录加载dll
Assembly.LoadFile 完整路径的加载 可以是别的目录 加载不会错,但是如果没有依赖项,使用的时候会错
Assembly.LoadFrom 带后缀或者完整路径
一般选用Assembly.Load 即可,只需要保持被加载的dll 和依赖的dll和应用程序的dll目录一致即可。这个开发环境下和生产环境下的目录请注意下,开发环境一般在 bin/debug 目录下,生产环境直接就在bin 目录下吗
Assembly.LoadFile 这个因为引用的是外部绝对地址,所以很有可能造成找不到依赖性的问题,所以这个不推荐用
定义一个基类或者是接口,然后需要反射创建的类型都继承这个基类或者是接口,便于反射的时候创建的实例统一类型为基类或者是接口
TypeOf 和 GetType 的区别为,typeof 针对的是类名或者是接口名,而GetType则是针对更具体的实例。
Type type = assembly.GetType("Ruanmou.DB.MySql.MySqlHelper");//2 获取类型信息
object oDBHelper = Activator.CreateInstance(type);//3 创建对象
assembly.GetType("Ruanmou.DB.MySql.MySqlHelper") 这个传入类名称(包括命名空间),可以获得到一个类型
Activator.CreateInstance(type) 根据上面获得到的类型,创建一个实例化对象
工厂方法+反射 创建一个实例化对象,DLL名称和类名称都通过配置的方式,通过动态读取来灵活的创建实例对象,可以配置多个Helper,然后修改CreateHelper 方法,通过参数控制读取某一个helper的配置文件即可,其实这就是一个简单的IOC实现的DEMO,达到了可配置可扩展的效果

反射性能测试
通过1000000次的循环反射创建实例的结果来看,将反射放在循环外面和循环里面两个地方,性能差异还是很大的
所以我们在使用反射创建实例的时候,一定要注意反射的作用域和使用范围,减少对性能的损耗

反射与单例模式
普通的单例模式创建无法访问单例类的私有构造函数,而通过反射方式创建的单例类的实例每次都会调用一次类的私有构造函数,所以说反射会破坏单例模式,打破了游戏规则,所以要慎用反射创建单例类的实例哦

反射调用构造函数与创建泛型类实例
上面提到通过反射创建类实例的时候,基本调用的都是类的无参数构造函数,那么如何调用有参数的构造函数呢
请看下图中,反射的时候通过指定构造函数的参数类型和数量来区分,构造函数的参数通过一个object 数组来指定
泛型类的实例化比普通类的实例化要复杂一个步骤,除了加载dll之外,在获得类名称的时候,需要通过占位符的方式指定泛型参数数量,下一步再指定泛型参数的具体类型,也就是泛型的延迟特性的体现,调用的时候需要指定具体参数类型的体现。然后下一步就是通过反射创建泛型实例

反射调用实例的方法
通过GetMethods 方法可以获得到这个实例的所有方法,然后遍历输出即可查看到
如下图,调用方法的时候,如果方法没有参数,则在Method Invoke的时候,传递一个实例,第二个参数就是方法的参数列表,给null即可。
如果调用的方法有参数,则在InVoke 的时候通过object 数组给定对应的参数列表即可。调用静态方法的时候,可以不传递实例,也可以传递实例。因为静态方法是不需要实例化就可以执行的。
还有一种情况就是调用重载方法,可能会出现无法识别调用那个具体的方法,那么这个时候就需要在反射的时候通过Type数组指定方法的参数个数和参数类型,参数个数和参数类型顺序一定要正确,然后在Invoke的时候,通过object数组给定type数组对应的参数个数和参数类型即可调用重载的方法。
反射调用私有方法和泛型方法
调用私有方法的时候,需要调用GetMethod的另一个重载的方法,指定BindingFlags.Instance | BindingFlags.NonPublic参数,表示搜索包括实例的非公共成员,也就是私有方法,其他的和普通方法类似,通过object数组给定参数列表即可
泛型类里的泛型方法的调用,首先按照上文的方式创建一个泛型实例,然后获取这个实例的泛型方法,然后通过MakeGenericMethod方法指定泛型参数具体类型类表,然后通过object 数组参数列表调用方法即可

字段级别的反射
下图的场景,就是将一个实例化的对象的值映射到另一个对象上去,这两个对象的字段属性都一样或者部分一样
以往我们往往采取硬编码的方式,一个个的为新对象的属性赋值,但是现在我们可以通过字段反射的方式来循环赋值
提高了编码效率,封装成一个泛型方法的话,那就可以成为一个通用的方法了

欢迎分享,(联系QQ/微信:1379998143)