• 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())
    {
         foreachvar 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);
                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:调用普通方法的泛型方法

    1  //类的泛型方法调用
    2 Type genericMethodType = assembly.GetType("MyReflection.GenericMethod");
    3 var objectGeneric = Activator.CreateInstance(genericMethodType);
    4 MethodInfo genericMethod = genericMethodType.GetMethod("Show");
    5 MethodInfo genericMethodNew = genericMethod.MakeGenericMethod(typeof(int), typeof(int));
    6 //一定要用genericMethodNew进行调用
    7 genericMethodNew.Invoke(objectGeneric, new object[] { 1, 4 });

    四:反射的用途:

    1:使用Assembly定义和加载程序集,加载在程序集清单中列出模块,以及从此程序集中查找类型并创建该类型的实例。 
    2:使用Module了解包含模块的程序集以及模块中的类等,还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。 
    3:使用ConstructorInfo了解构造函数的名称、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。 
    4:使用MethodInfo了解方法的名称、返回类型、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。
    5:使用FiedInfo了解字段的名称、访问修饰符(如public或private)和实现详细信息(如static)等,并获取或设置字段值。
    6:使用EventInfo了解事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等,添加或移除事件处理程序。 
    7:使用PropertyInfo了解属性的名称、数据类型、声明类型、反射类型和只读或可写状态等,获取或设置属性值。 
    8:使用ParameterInfo了解参数的名称、数据类型、是输入参数还是输出参数,以及参数在方法签名中的位置等。

    五:反射类以及属性的介绍:
     
    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():返回FieldInfo类型,用于取得该类的字段(成员变量)的信息
            GetInterface(), GetInterfaces():返回InterfaceInfo类型,用于取得该类实现的接口的信息
            GetMember(), GetMembers():返回MemberInfo类型,用于取得该类的所有成员的信息
            GetMethod(), GetMethods():返回MethodInfo类型,用于取得该类的方法的信息
            GetProperty(), GetProperties():返回PropertyInfo类型,用于取得该类的属性的信息
        可以调用这些成员,其方式是调用Type的InvokeMember()方法,或者调用MethodInfo, PropertyInfo和其他类的Invoke()方法。 
     
    六:普通方法和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); //不要父类的属性,只要子类的属性
    坚持就是胜利! 如有问题,请反馈微信loverwangshan
  • 相关阅读:
    一点点
    第四章:检查产品说明书
    这是一个动画效果,一个圆在桌面上动
    border-image的拉伸和平铺
    用js实现左右阴影的切换
    伪样式:hover ,:active,:focus
    画一个DIV并给它的四个角变成圆形,且加上阴影
    【转】asp.net 项目在 IE 11 下出现 “__doPostBack”未定义 的解决办法
    Full postback triggered by LinkButton inside GridView inside UpdatePanel
    苹果IOS开发者账号的区别,企业账号,个人账号,公司团队账号,教育账号
  • 原文地址:https://www.cnblogs.com/loverwangshan/p/9883243.html
Copyright © 2020-2023  润新知