欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

浅谈.Net反射

程序员文章站 2022-10-25 12:31:22
一.何为反射? reflection; 程序集包含模块,而模块包含类型,类型又包含成员。反射则提供了封装程序集、模块和类型的对象。我们可以使用反射动态地创建类型的实例...

一.何为反射?

reflection; 程序集包含模块,而模块包含类型,类型又包含成员。反射则提供了封装程序集、模块和类型的对象。我们可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。然后,就可以调用类型的方法或访问其字段和属性。

下图很好的解释了程序集和模块,类型等之间的关系: 浅谈.Net反射

 

 

二.那些反射用到的类


1)反射核心类:system.type类

system. type类包装了类型,因此是整个反射子的核心,这个类中包含了很多属性和方法,使用这些属性和方法可以在运行时得到类型的信息. type类派生于system.reflection.memberinfo抽象类.(关于memberinfo,msdn上有解释,大家可以了解一下) 除了memberinfo类定义的方法和属性之外,type类自己也添加了许多方法和属性:如下表是常用的一些方法:
浅谈.Net反射

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文件时新增还是减少的情况了,有点一劳永逸的味道。

 

在真正用的过程中,反射回合委托,泛型,特性等等结合使用,这都是需要进一步研究学习的地方