美文网首页
反射reflection使用解读

反射reflection使用解读

作者: 毛毛虫同学 | 来源:发表于2021-01-14 17:05 被阅读0次

    一、 理论

    反射Reflection:System.Reflection,是.Net Framework提供的一个帮助类库,可以读取并使用metadata
    IL: 也是一种面向对象语言
    metadata元数据:数据清单,描述DLL/exe里面的各种信息,CLR运行时会先看metadata

    二、 反射使用

    #region 普通用法
    {
      IDBHelper iDBHelper = new MySqlHelper();
      iDBHelper.Query();
    }
    #endregion
    #region Reflection用法
    {
      //1. 动态加载一个完整的dll/exe名称,不需要后缀,从根目类所在的路径进行查找,同名dll和exe,dll优先
      Assembly assemnly = Assembly.Load("DB.MySql");
      //完整路径
      Assembly assemnly = Assembly.LoadFile(@"D:\reflection\bin\debug\DB.MySql".dll);
      //当前路径
      Assembly assemnly = Assembly.LoadFrom("DB.MySql.dll");
      //获取类型,完整类名称
      Type type = assemnly.GetType("DB.MySql.MySqlHelper");
      object oDbHelper = Activator.CreateInstance(type);
      //有参数的构造函数
      object oDbHelper = Activator.CreateInstance(type,new object[]{ 123 });
      //为什么不能直接Query?实际上是有Query方法的,只是因为编译器不认可
      //oDbHelper.Query();
    
      //类型转换,不报错,类型不对就返回null
      IDbHelper iDbHelper = oDbHelper as IDbHelper;
      iDbHelper.Query();
      //不做类型转换
      var method  = type.GetMethod("Query");
      method.Invoke(oDbHelper,null);
     //有重载方法?
      var method  = type.GetMethod("Query",new Type[]{ typeof(int),typeof(string) });
      method.Invoke(oDbHelper,new object[]{123,"123"});
      //调用带参数方法
       method.Invoke(oDbHelper,new object[]{123});
      //静态方法可以不传实例
       method.Invoke(null,new object[]{123,"123"});
    
      //dynamic编译器不检查,运行时才检查
      dynamic dDbHelper = Activator.CreateInstance(type);
      dDbHelper.Query();
     
      //查看全部类和方法
      foreach(var type in assembly.GetTypes()
      {
         console.WriteLine(type.Name);//类名
         foreach(var method in type.GetMethods())
         {
            console.WriteLine(method.Name);//方法
         }
         foreach(var construct in type.GetConstructors())
         {
            console.WriteLine(construct .Name);//构造函数
         }
      }
    }
    #endregion
    

    三、 使用更复杂了?封装工厂

    {
      //Reflector + Factory + Config
      //可配置,如果需要换成SqlServer处理时,可以直接改配置文件
      //实现类必须在目录下面
      //可扩展:完全不修改原有代码,只是增加新的实现,复制dll,修改配置文件,就可以支持新功能
      //反射的动态加载和动态创建对象,以及配置文件结合
      IDbHelper iDbHelper = SimpleFactory.CreateInstance();
      iDbHelper.Query();
    }
    public class SimpleFactory
    {
       private static string IDBHelperConfig = ConfigurationManager.AppSetting["IDBHelperConfig"];
    
       private static string DllName = IDBHelperConfig.Split(',')[0];
       private static string TypeName = IDBHelperConfig.Split(',')[1];
       public static IDBHelper CreateInstance()
       {
           Assembly assemnly = Assembly.Load(DllName);
           Type type = assemnly.GetType(TypeName );
           object oDbHelper = Activator.CreateInstance(type);
           IDbHelper iDbHelper = oDbHelper as IDbHelper;
           return iDbHelper;
       }
    }
    

    四、应用场景

    1、MVC:浏览器只告诉了服务器Controller(类型)名称和方法名称
    MVC在启动时会先加载--扫描全部的dll--找到全部的Controller--存起来--请求来的时候,用Controller来匹配的
    MVC局限性--Action如果重载了,反射是无法区分的----MVC如果重载方法只能通过HttpMethod+特性区分HttpPost/HttpGet
    2、AOP

    //根据dll名称、类型名称、方法名称就可以调用方法
    

    五、延升,反射调用私有方法,调用泛型方法

    {
     //调用私有方法
     Assembly assembly = Assembly.Load("DB.SqlServer");
     Type type = assemnly.GetType("DB.MySql.MySqlHelper");
     object oDbHelper = Activator.CreateInstance(type);
     var method = type.GetMethod("Show4",BindingFlag.Instance | BindingFlag.NonPublic);
     method.Invoke(oDbHelper,null);
    }
    {
    //泛型方法
     Assembly assembly = Assembly.Load("DB.SqlServer");
     Type type = assemnly.GetType("DB.MySql.MySqlHelper");
     object oDbHelper = Activator.CreateInstance(type);
     var method = type.GetMethod("Show");
     method.MakeGenericMethod(new Type[]{typeof(string),typeof(int)});
     method.Invoke(oDbHelper,new object[]{"123",123});
    }
    {
    //泛型类下的泛型方法
     Assembly assembly = Assembly.Load("DB.SqlServer");
     Type type = assemnly.GetType("DB.MySql.MySqlHelper`1").MakeGenericType(typeof(int));
     object oDbHelper = Activator.CreateInstance(type);
     var method = type.GetMethod("Show");
     method.MakeGenericMethod(new Type[]{typeof(string),typeof(int)});
     method.Invoke(oDbHelper,new object[]{"123",123});
    }
    
    image.png

    六、总结
    反射的优缺点:
    优点:动态
    缺点:1.使用麻烦(封装解决) 2.避开编译器检查 3.性能问题
    测试:100万次循环,普通方法 41ms,反射 6512ms
    但是换个角度分析下,100次循环,反射耗时0.65ms
    反射可以缓存优化,dll加载和类型获取只执行一次,
    100万次循环,普通方法 48ms 反射 103ms

    MVC--Asp.net--ORM--IOC--AOP都在用反射,几乎都用缓存
    MVC&ORM 启动都很慢,完成了很多初始化,反射信息,后面启动就很快

    相关文章

      网友评论

          本文标题:反射reflection使用解读

          本文链接:https://www.haomeiwen.com/subject/dhyygktx.html