浅谈.Net反射
程序员文章站
2022-10-25 12:31:22
一.何为反射?
reflection; 程序集包含模块,而模块包含类型,类型又包含成员。反射则提供了封装程序集、模块和类型的对象。我们可以使用反射动态地创建类型的实例...
一.何为反射?
reflection; 程序集包含模块,而模块包含类型,类型又包含成员。反射则提供了封装程序集、模块和类型的对象。我们可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。然后,就可以调用类型的方法或访问其字段和属性。
下图很好的解释了程序集和模块,类型等之间的关系:
二.那些反射用到的类
1)反射核心类:system.type类
system. type类包装了类型,因此是整个反射子的核心,这个类中包含了很多属性和方法,使用这些属性和方法可以在运行时得到类型的信息. type类派生于system.reflection.memberinfo抽象类.(关于memberinfo,msdn上有解释,大家可以了解一下) 除了memberinfo类定义的方法和属性之外,type类自己也添加了许多方法和属性:如下表是常用的一些方法:2)system.reflection.assembly类
通过assembly可以动态加载程序集,并查询程序集内部信息.assembly中有三种方法加载程序集:load,loadform,loadfile. *如果引用了命名空间,则就直接用load方法,参数里写上命名空间+类名就可加载。 *若仅仅知道一个dll文件,则就要用loadfrom方法,参数里直接填写完整的路径。loadfrom只能用于加载不同标识的程序集,即唯一的程序集,不能加载标识相同但路径不同的程序集。 * loadfile,加载指定路径上的程序集文件;与上述两方法不同的是:它不会加载此程序集中引用的其他的程 序集,且不会加载相同标识的程序集。 举例://assembly通过此类可以加载操纵一个程序集,并获取程序集内部信息 assembly assembly = assembly.load("myassembly"); //引用命名空间 assembly assembly2 = assembly.loadfrom("d:\testdll.dll"); assembly dll = assembly.loadfile(environment.currentdirectory + "\\testdll.dll"); //通过dll文件去反射其中所有的类型,但不会加载引用的程序集
三.如何使用反射?
1)要引用的程序集和需要程序集的程序在同一目录时,不需要加载程序集,直接可以获取其中的类型.举例:
type math = type.gettype("testdll.math", true); //获取类型 methodinfo method = math.getmethod("add"); //获取testdll.math中的方法add int count = (int)method.invoke(null, new object[] { 10, 20 }); //给add方法传参数并去调用方法add console.writeline("invoke method:" + count.tostring()); console.readline();
2)要引用的程序集合需要程序集不在同一目录中时,先要加载程序集,才能获取其中的类和类的方法等。举例:
assembly dll = assembly.loadfile(environment.currentdirectory + "\\testdll.dll"); //通过dll文件去反射其中所有的类型,但不会加载引用的程序集 //environment.currentdirectory 属性:获取或设置当前工作目录的完全限定路径 type math = dll.gettype("testdll.math", true); //获取类型 methodinfo method = math.getmethod("add"); //获取testdll.math中的方法add int count = (int)method.invoke(null, new object[] { 10, 20 }); //给add方法传参数并去调用方法add console.writeline("invoke method:" + count.tostring()); console.readline();
3)反射+配置文件
看过大话设计模式的,都知道在抽象工厂模式中.小菜在大鸟的指点下,用简单工厂,再用反射,再用配置文件,一步步将抽象工厂改装, 使得抽象工厂的缺点和个各类之间的耦合性都大大降低.
在不用反射+配置文件时,抽象工厂的问题是:
*如果需要增加多个,就要增加多个类,更麻烦。
在使用反射+配置文件后,抽象工厂的改变是:
*如果需要更换数据库,不需改变代码,只需要修改配置文件中db的值。
小结:反射技术的使用去除了switch或if,解除分支判断的耦合。在这里,反射可以说是简化了工厂的实现。
4)项目实践
在前段时间的项目开发中,就用到了反射。这里的用法和上述介绍的情况是一样的。用assembly类的load方法去加载程序集,用gettype去获取类型,getmethod去获取方法,invoke去调用方法,最后用savechanges去提交数据。举例://ef:就是让ef上下文保存了一下。不适合于集群(后期使用key,value保存在分布式缓存中,key为guid) public int savechanges() { //return dbcontextfactory.getcurrentdbcontext().savechanges(); string strassembly = configurationmanager.appsettings["dalassembly"]; string strdbcontextfactoryclassfullename = configurationmanager.appsettings["dbcontextfactoryclassfullename"]; assembly assembly = assembly.load(strassembly); type type = assembly.gettype(strdbcontextfactoryclassfullename); methodinfo methodinfo = type.getmethod("getcurrentdbcontext"); return ((dbcontext)methodinfo.invoke(null, null)).savechanges(); }
四.为什么要用反射?
反射与引用
相比较下,引用执行效率高,但是当你引用的dll文件很多的时候,一遍遍的引用dll...,那就不是什么好事了。 反射呢,虽执行效率低,但在上述情况出现时,它只需动态反射一次dll文件,不用去管dll文件时新增还是减少的情况了,有点一劳永逸的味道。
在真正用的过程中,反射回合委托,泛型,特性等等结合使用,这都是需要进一步研究学习的地方
上一篇: 北京通教寺