zoukankan      html  css  js  c++  java
  • C# 反射 Reflection Assembly

    本章节带来的是反射,反射反射程序员的快乐。

    一、什么叫反射

    反射:是.net Framework提供给的一个方面metadata的帮助类,可以获取信息并且使用

    反射的有点:动态

    反射的缺点:1:稍微麻烦 2:能避开编译器的检查 3:性能损耗

    二、反射如何使用:
    具体和私用如下:

    复制代码
    #region 反射的加载方式
    ////获取当前路径下面的dl或者exe,不带后缀(MyReflection.exe 是编译后生成的exe执行文件),从Exe所在的路径进行查找
    Assembly assembly = Assembly.Load(@"MyReflection");
    //获取当前路径下面的dl或者exe
    Assembly assemblyFrom = Assembly.LoadFrom(@"D:MyReflectioninDebugMyReflection.exe");
    //获取当前路径下面的dl或者exe
    Assembly assemblyFile = Assembly.LoadFile(@"D:MyReflectioninDebugMyReflection.exe"); 
    foreach (var item in assembly.GetModules())
    {
       //Modules当前的exe或者dll的名字(MyReflection.exe)
       Console.WriteLine(item.Name); 
    }
    //当前所包含的实体类(IDBHelper,SqlServerHelper,Program)
    foreach (var item in assembly.GetTypes())
    {
         foreach(var method in item.GetMethods()){
              Console.WriteLine(method.Name);      
          }
        Console.WriteLine(item.Name);
    }
    
    foreach (var item in assembly.GetCustomAttributes())
    {
        Console.WriteLine(item.ToString());
    }
    //获取到有多个构造函数
    foreach (var ctor in type.GetConstructors())
    {
    Console.WriteLine(ctor.GetParameters());
    //获取构造函数里面的参数
    foreach (var item in ctor.GetParameters())
    {
    Console.WriteLine(item.ParameterType);
    }
    }
    #endregion
    复制代码

    通过反射创建一个方法:

    复制代码
    /// <summary>
        /// 反射得到一个对象
        /// </summary>
        public class SimpleFactory
        {
            //读取配置文件AppSetting里面的key
            // <appSettings>
            // <add key = "DbConfig" value="MyReflection,MyReflection.MySqlServerHelper"/>
            //</appSettings>
            private static string ConfigStr = ConfigurationManager.AppSettings["DbConfig"];
            private static string DllName = ConfigStr.Split(',')[0];  //命名空间
            private static string TypeName = ConfigStr.Split(',')[1]; //类型要完整命名空间+类名
            public static T CreateInstance<T>()
            {
                Assembly assembly = Assembly.Load(DllName);//加载dll
                Type type = assembly.GetType(TypeName);//获取类型
                var objectInstance = Activator.CreateInstance(type);
                return (T)objectInstance; //要强制转换一下,因为牵涉到编译性语言和运行时语言
            }
        }
    复制代码

    调用的时候如下:

    var mysqlServerHelper = SimpleFactory.CreateInstance<MySqlServerHelper>();
    mysqlServerHelper.Query();

    三、反射调用多构造函数,调用私有构造函数(破坏单例),调用泛型类

    首先创建一个实体类,包含有参无参构造函数,然后有参无参的方法,如下:

    复制代码
    /// <summary>
        /// sqlServer
        /// </summary>
        public class SqlServerHelper : IDBHelper
        {
            //private SqlServerHelper()
            //{
            //    Console.WriteLine("私有构造函数");
            //}
            public SqlServerHelper()
            {
                Console.WriteLine("公有无参构造函数");
            }
            public SqlServerHelper(int iParam)
            {
                Console.WriteLine($"int的构造函数--{iParam}");
            }
            public SqlServerHelper(string sParam)
            {
                Console.WriteLine($"string的构造函数--{sParam}");
            }
            public SqlServerHelper(int iParam, string sParam)
            {
                Console.WriteLine($"int和string的构造函数--int={iParam} ;string={sParam}");
            }
    
            public void Show()
            {
                Console.WriteLine("Show");
            }
            public void Show1()
            {
                Console.WriteLine("Show1的无参构造函数");
            }
            public void Show1(int iParam)
            {
                Console.WriteLine($"Show1的int重载--{iParam}");
            }
            public void Show1(int iParam, string sParam)
            {
                Console.WriteLine($"Show1两参数 iparam={iParam};sParam={sParam}");
            }
            public static void Show5(string name)
            {
                Console.WriteLine($"静态方法---{name}");
            }
        }
    复制代码

    1:调用有参无参的public构造函数:

    复制代码
    Assembly assembly = Assembly.Load("MyReflection"); //获取当前路径下面的dl或者exe,不带后缀
    Type dbHelperType = assembly.GetType("MyReflection.SqlServerHelper"); //传完整名称获类型(命名空间+类名)
    //调用多个构造函数(有参,无参)
    var obSqlServerHelper = Activator.CreateInstance(dbHelperType); //无参的构造函数
    Activator.CreateInstance(dbHelperType, new object[] { 11 }); //int的构造函数
    Activator.CreateInstance(dbHelperType, new object[] { "testbywss" }); //调用string的构造函数
    Activator.CreateInstance(dbHelperType, new object[] { 123, "testbywss" }); //调用string的构造函数
    复制代码

    2:调用private构造函数:

    //私有构造函数
     Type singletonType = assembly.GetType("MyReflection.Singleton"); //传入完整名称获取类型(命名空间+类名)
     var object1 = Activator.CreateInstance(singletonType, true); //设置成true能调用私有/公布的构造函数,如果不设置则只能调用公有构造函数

    3:普通方法,静态方法,重载方法的调用:

    复制代码
    //普通方法
    MethodInfo methodInfo = dbHelperType.GetMethod("Show"); //调用单个普通的实例方法
    methodInfo.Invoke(obSqlServerHelper, null); //第一个参数:是应用对象,第二个参数:是方法需要的参数,如果没有则设置为null
    
     //静态方法调用
    MethodInfo staticMethodInfo = dbHelperType.GetMethod("Show5"); //调用单个普通的实例方法
    staticMethodInfo.Invoke(null, new object[] { "静态方法第一种调用方式" }); //第一个参数:是应用对象,如果是静态可以不用写;第二个参数:是方法需要的参数,如果没有则设置为null
    staticMethodInfo.Invoke(obSqlServerHelper, new object[] { "静态方法第二种调用方式" });

    //重载方法调用 MethodInfo method2 = dbHelperType.GetMethod("Show1", new Type[] { }); //调用无参的方法 method2.Invoke(obSqlServerHelper, null); MethodInfo method3 = dbHelperType.GetMethod("Show1", new Type[] { typeof(int) }); //int参数的方法 method3.Invoke(obSqlServerHelper, new object[] { 11 }); MethodInfo method4 = dbHelperType.GetMethod("Show1", new Type[] { typeof(int), typeof(string) }); //调用2个参数的方法,new Type[] { typeof(int), typeof(string) } 顺序一定要跟调用的方法的参数顺序保持一致 method4.Invoke(obSqlServerHelper, new object[] { 1111, "ddd" });
    复制代码

    4:调用泛型,首先要创建一个实体类如下:

    复制代码
    #region 泛型类
      public class GenericClass<T, W, F>
      {
            public void Show(T t, W w, F f)
            {
                Console.WriteLine($"t.type={t.GetType().Name};}");
            }
      }
    
        public class GenericMethod
        {
            public void Show<T, W, X>(T t, W w, X x)
            {
                Console.WriteLine($"t.type={t.GetType().Name};");
            }
        }
    
        public class GenericDouble<T>
        {
            public void Show<W, X>(T t, W w, X x)
            {
                Console.WriteLine($"t.type={t.GetType().Name};");
            }
        }
        #endregion
    复制代码

    然后调用泛型方法如下:

    复制代码
    //创建泛型
    Assembly assembly = Assembly.Load("MyReflection"); //获取当前路径下面的dl或者exe,不带后缀
    Type genericType = assembly.GetType("MyReflection.GenericClass`3"); //`3是泛型类需要的参数(占位符代表有三个类型参数)
    Type typeGenericNew = genericType.MakeGenericType(typeof(int), typeof(int), typeof(int)); //需要指定泛型类的类型
    GenericClass<int, int, int> oGeneric = (GenericClass<int, int, int>)Activator.CreateInstance(typeGenericNew);
    oGeneric.Show(1, 30, 60);
    
    Type genericType1 = assembly.GetType("MyReflection.GenericMethod"); //普通的类
    var genericMethod = Activator.CreateInstance(genericType1) as GenericMethod;
    genericMethod.Show<int, string, double>(1, "1", 2);
    复制代码

    5:调用私有方法(破坏单例)

    复制代码
    //私有方法
    //调用私有方法,有参数
    MethodInfo method5 = dbHelperType.GetMethod("Show5", BindingFlags.NonPublic | BindingFlags.Instance);
    method5.Invoke(obSqlServerHelper, new object[] { 5.0 });
    
    //私有方法,无参数
    MethodInfo method6 = dbHelperType.GetMethod("Show6", BindingFlags.NonPublic | BindingFlags.Instance);
    method6.Invoke(obSqlServerHelper, null);
    复制代码

    6:调用普通方法的泛型方法

    复制代码
    //类的泛型方法调用
    Type genericMethodType = assembly.GetType("MyReflection.GenericMethod");
    var objectGeneric = Activator.CreateInstance(genericMethodType);
    MethodInfo genericMethod = genericMethodType.GetMethod("Show");
    //同样需要指定泛型方法的类型
    MethodInfo genericMethodNew = genericMethod.MakeGenericMethod(typeof(int), typeof(int));
    //一定要用genericMethodNew进行调用
    genericMethodNew.Invoke(objectGeneric, new object[] { 1, 4 });
    复制代码

    四:反射的用途:

    1:使用Assembly定义和加载程序集,加载在程序集清单中列出模块,以及此程序集中查找类型并且创建该类型的实力。

    2:使用Module了解包含模块的程序集模块中的类等,还可以获取在模块上定义IDE所有全局方法或其他定义的非全局方法。

    3:使用ConstructorInfo 了解构造函数的名字、参数、访问修饰符(如public 或private)和实现详细信息(如abstract或virtual)等。

    4:使用MethodInfo 了解方法的名字、返回的类型、参数、参数类型、访问修饰符(如public 或private)和实现详情信息(如abstract或virtual)等。

    5:使用FiedInfo了解字段名称、访问修饰符(如public 或private)和实现详细信息(如static)等,并获取或设置字段值。

    6:使用PropertyInfo了解属性的名字、数据类型、声明类型、反射类型和只读或可写状态等,获取或设置属性值。

    7:使用EventInfo了解事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等,添加或移除事件处理程序。

    8:使用ParameterInfo了解参数的名称、数据类型、是输入参数还是输出参数,以及参数在方法签名中位置等。

    9:使用Attribute了解特性的名字、使用特性的方法属性等。(点击跳转 C# 自定义特性Attribute的使用

    五、反射类以及属性的介绍:
     
    1:反射用到的主要类:
      System.Type类 通过这个类可以访问任何定义数据类型的信息。
      System.Reflection.Assembly 它可以访问给定程序集的信息,或者把这个程序集加载到程序中。
     
    2:Type类的属性:
      Name 数据类型名称
      FullName 数据类型的完全限定名(包括命名空间名)
      Namespace 定义数据类型的命名空间名
      IsAbstract 是否是抽象
      IsArray 是否是数组
      IsClass 是否是类
      IsEnum 是否是枚举
      IsInterface 是否是接口
      IsPublic 是否是公开的
      IsSealed 是否是密封的
      IsValueType 是否是值类型
      IsGenericType 是否是泛型
     
    复制代码
    Console.WriteLine("*********************字段和属性***********************");
      People people = new People()
      {
        ID = 111,
        Name = "名字",
        Description = "描述"
      };
     Type typePeople = typeof(People);
     object oPeople = Activator.CreateInstance(typePeople); //new 一个新的对象
     //得到所有的字段public声明,但是么有set和get方法
     foreach (var item in typePeople.GetFields())
     {
        Console.WriteLine($"Name1={item.Name};value1={item.GetValue(people)}");
     }
    
    //得到所有的属性(有set和get的属性)
    foreach (var item in typePeople.GetProperties())
    {
      if (item.Name.Equals("Id"))
      {
         item.SetValue(oPeople, 888);
      }
      else if (item.Name.Equals("Name"))
      {
        item.SetValue(oPeople, "人民");
      }
     Console.WriteLine($"Name={item.Name};value={item.GetValue(oPeople)}");
    }
    复制代码

    3:Type类的方法

      GetConstructor(),GetConstructors():返回ConstructorInfo类型,用于取得该类的构造函数的信息

      GetEvent(),GetEvents():返回EventInfo类型,用于取得该类的事件的信息

      GetField(),GetFields():返回FielInfo类型,用于取得该类的字段(成员变量)的信息

      GetInterface(),GetInterfaces();返回InterfaceInfo类型,用于获得该类实现的接口信息

      GetMember(),GetMembers();返回MemberInfo类型,用于取得该类的所有成员信息

      GetMethod(),GetMethods();返回MethodInfo类型,用于取得该类的方法信息

      GetProperty(),GetProperties();返回PropertyInfo类型,用于取得该类的属性的信息

    六:普通方法和Reflection性能的比较

    复制代码
    public class MySqlServerHelper
        {
            public MySqlServerHelper()
            {          
            }      
            public void Query()
            {
    
            }
        }
    复制代码
    复制代码
    public class Monitor
     {
            public static void Show()
            {
                Console.WriteLine("*******************Monitor*********");
                long commonTime = 0;
                long reflectionTime = 0;
                {
                    //时间测量工具
                    Stopwatch watch = new Stopwatch();
                    watch.Start();
                    for (int i = 0; i < 1000000; i++)
                    {
                        MySqlServerHelper dbHelper = new MySqlServerHelper();
                        dbHelper.Query();
                    }
                    watch.Stop();
                    commonTime = watch.ElapsedMilliseconds; //毫秒
                }
                {
                    Stopwatch watch = new Stopwatch();
                    watch.Start();
                    //1:动态加载
                    Assembly assembly = Assembly.Load("MyReflection");
                    //2:获取类型
                    Type type = assembly.GetType("MyReflection.MySqlServerHelper");
                    for (int i = 0; i < 1000000; i++)
                    {
                        MySqlServerHelper oDbHelper =(MySqlServerHelper)Activator.CreateInstance(type);
                        oDbHelper.Query();
                    }
                    watch.Stop();
                    reflectionTime = watch.ElapsedMilliseconds;
                }
                Console.WriteLine($"reflectionTime={reflectionTime};commonTime={commonTime}");
            }
        }
    复制代码

    然后调用后发现: 100万次相差30倍左右,所以反射的是很耗性能,但是如果分布到每次则相差几毫秒,所以这个性能影响可以忽略掉!

    七:继承后的子类,只需要获取子类的属性:

    t.GetType().GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public); //不要父类的属性,只要子类的属性

  • 相关阅读:
    shell进行mysql统计
    java I/O总结
    Hbase源码分析:Hbase UI中Requests Per Second的具体含义
    ASP.NET Session State Overview
    What is an ISAPI Extension?
    innerxml and outerxml
    postman
    FileZilla文件下载的目录
    how to use webpart container in kentico
    Consider using EXISTS instead of IN
  • 原文地址:https://www.cnblogs.com/IT-Ramon/p/12061058.html
Copyright © 2011-2022 走看看