浅谈.Net反射

一.何为反射?

    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,加载指定路径上的程序集文件;与上述两方法不同的是:它不会加载此程序集中引用的其他的程
序集,且不会加载相同标识的程序集。
    
    举例:
<span style="font-family:FangSong_GB2312;">      //Assembly通过此类可以加载操纵一个程序集,并获取程序集内部信息
      Assembly assembly = Assembly.Load("MyAssembly"); //引用命名空间
      Assembly assembly2 = Assembly.LoadFrom("D:\testDll.dll"); 
      Assembly dll = Assembly.LoadFile(Environment.CurrentDirectory + "\\testDll.dll");                                           //通过dll文件去反射其中所有的类型,但不会加载引用的程序集</span>

三.如何使用反射?

1)要引用的程序集和需要程序集的程序在同一目录时,不需要加载程序集,直接可以获取其中的类型.举例:

<span style="font-family:FangSong_GB2312;font-size:18px;">      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();</span>


2)要引用的程序集合需要程序集不在同一目录中时,先要加载程序集,才能获取其中的类和类的方法等。举例:

<span style="font-family:FangSong_GB2312;">      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();</span>


3)反射+配置文件

    看过大话设计模式的,都知道在抽象工厂模式中.小菜在大鸟的指点下,用简单工厂,再用反射,再用配置文件,一步步将抽象工厂改装, 使得抽象工厂的缺点和个各类之间的耦合性都大大降低.  
   

    在不用反射+配置文件时,抽象工厂的问题是: 
       *如果需要增加多个数据库,就要增加多个类,更麻烦。

 
    在使用反射+配置文件后,抽象工厂的改变是:
       *如果需要更换数据库,不需改变代码,只需要修改配置文件中DB的值。
 
   小结:反射技术的使用去除了switch或if,解除分支判断的耦合。在这里,反射可以说是简化了工厂的实现。

4)项目实践

  在前段时间的项目开发中,就用到了反射。这里的用法和上述介绍的情况是一样的。用Assembly类的Load方法去加载程序集,用GetType去获取类型,GetMethod去获取方法,Invoke去调用方法,最后用SaveChanges去提交数据。举例:
   
<span style="font-family:FangSong_GB2312;">
        //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();
        }</span>

四.为什么要用反射?

 反射与引用

    相比较下,引用执行效率高,但是当你引用的dll文件很多的时候,一遍遍的引用dll...,那就不是什么好事了。 反射呢,虽执行效率低,但在上述情况出现时,它只需动态反射一次dll文件,不用去管dll文件时新增还是减少的情况了,有点一劳永逸的味道。


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



郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。