反射

SunnyFan大约 10 分钟约 2984 字

反射

反射/反编译工具/高级语言到计算机语言的历程

反射创建对象

    IDBHelper dBHelper = new SqlServerHelper();
    IDBHelper dBHelper = new MySqlHelper();
    dBHelper.Query();
    Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");//dll名称
    Assembly assembly1 = Assembly.LoadFile(@"D\MyReflecttion\bin\Debug\net5.0\Business.DB.SqlServer.dll");//dll名称
    Assembly assembly2 = Assembly.Load("Business.DB.SqlServer");//dll名称
    
    foreach (Type type in assembly.GetTypes())
    {
        Console.WriteLine(type.FullName);
        foreach (var method in type.GetMethods())
        {
            Console.WriteLine(method.Name);
        }
        foreach (var fild in type.GetFields())
        {
            Console.WriteLine(fild.Name);
        }
    }
    
    Type type = assembly.GetType("Business.DB.SqlServer.SqlServerHelper");
    
    object? oInstance = Activator.CreateInstance(type);
    object? oInstanc1= Activator.CreateInstance("Business.DB.SqlServer.dll", "Business.DB.SqlServer.SqlServerHelper");
    
    //a.oInstance.Query();//报错了: 因为oInstance当做是一个object类型,object类型是没有Query方法;C#语言是一种强类型语言;编译时决定你是什么类型,以左边为准;不能调用是因为编译器不允许;实际类型一定是SqlServerHelper;
    //b.如果使用dynamic 作为类型的声明,在调用的时候,没有限制;
    //c.dynamic :动态类型:不是编译时决定类型,避开编译器的检查;运行时决定是什么类型
    //d.dynamic dInstance = Activator.CreateInstance(type);
    //e.dInstance.Query();
    ////f.dInstance.Get(); //报错了--因为SqlServerHelper没有Get方法
    
    SqlServerHelper helper = (SqlServerHelper)oInstance; //不建议这样转换--如果真实类型不一致--会报报错; 
    IDBHelper helper = oInstance as IDBHelper;//如果类型一直,就转换,如果不一致;就返回null
    
    helper.Query();
    ////经过5步骤;千辛万苦--终于调用到了Query方法;
    ////问题:反射不是很牛逼吗?无处不在?就这?
    ////1.代码好多---在面向对象以后,代码多不是事儿;
    ////2.继承  封装   多态
    ////3.代码多久封装 
    
    //IDBHelper helper1 = SimpleFactory.CreateInstance();
    //helper1.Query();
    //1.如果公司来了一个新的技术经理:---SqlServer----MySql
    //2.传统方式,必须要修改代码---必须要重新发布  编译   发布到服务器---步骤就很多
    //3.反射实现:断开了对普通类的依赖;依赖于配置文件+接口(抽象)
    
    //SqlServer---MySql
    //a.  按照接口约定实现一个Mysql帮助类库
    //b.  Copy  dll 文件到执行目录下
    //c.  修改配置文件
    
    //结果:不同功能的灵活切换---程序的课配置;
    //      如果经理--MySql--Oracle
    //      如果一个新的功能还不存在,只需要把功能实现、dll Copy到执行目录下,修改配置文件---不需要停止程序的运行; 扩展一个新的功能进来;
    //      程序的课可扩展
    

    反射黑科技---反射可以做到普通方式做不到的事儿;--反射破坏单例

    {
        //new  Singleton();
        Singleton singleton1 = Singleton.GetInstance();
        Singleton singleton2 = Singleton.GetInstance();
        Singleton singleton3 = Singleton.GetInstance();
        Singleton singleton4 = Singleton.GetInstance();
        Console.WriteLine(object.ReferenceEquals(singleton1, singleton2));
        Console.WriteLine(object.ReferenceEquals(singleton2, singleton3));
        Console.WriteLine(object.ReferenceEquals(singleton1, singleton4));
    }
    //new Singleton();
    {
        Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");
        Type type = assembly.GetType("Business.DB.SqlServer.Singleton");
        Singleton singleton1 = (Singleton)Activator.CreateInstance(type, true);
        Singleton singleton2 = (Singleton)Activator.CreateInstance(type, true);
        Singleton singleton3 = (Singleton)Activator.CreateInstance(type, true);
        Singleton singleton4 = (Singleton)Activator.CreateInstance(type, true);
        Console.WriteLine(object.ReferenceEquals(singleton1, singleton2));
        Console.WriteLine(object.ReferenceEquals(singleton2, singleton3));
        Console.WriteLine(object.ReferenceEquals(singleton1, singleton4));
    }
    

    反射调用方法+反射创建对象的升级篇

    {
        Type type = null;
        Activator.CreateInstance();//访问的是无参数构造函数创建对象;
        //如何访问带参数的构造函数呢? 
        Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");
        Type type = assembly.GetType("Business.DB.SqlServer.ReflectionTest");
        //a. 调用无参数构造函数的
        object noParaObject = Activator.CreateInstance(type);
        //b. 调用有参数的---需要传递一个object类型的数组作为参数,参数按照从昨往右匹配;严格匹配,按照参数的类型去执行对应的和参数类型匹配的构造函数,如果没有匹配的---报异常
        object paraObject = Activator.CreateInstance(type, new object[] { 123 });
        object paraObject1 = Activator.CreateInstance(type, new object[] { "纯洁的逗比" });
        object paraObject2 = Activator.CreateInstance(type, new object[] { 234, "丸印" });
        object paraObject3 = Activator.CreateInstance(type, new object[] { "Richard", 456 });
    }
    
    //1.获取方法odInfo
    //2.执行MethodInfo 的Invoke方法,传递方法所在的类的实例对象+参数
    {
        //a. 调用五参数的方法
        Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");
        Type type = assembly.GetType("Business.DB.SqlServer.ReflectionTest");
        object oInstance = Activator.CreateInstance(type);
        MethodInfo show1 = type.GetMethod("Show1");
        show1.Invoke(oInstance, new object[] { });
        show1.Invoke(oInstance, new object[0]);
        show1.Invoke(oInstance, null);
    }
    // b. 调用有参数的方法---重载方法--需要通过方法参数类型类区别方法,传递参数--严格匹配参数类型
    {
        Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");
        Type type = assembly.GetType("Business.DB.SqlServer.ReflectionTest");
        object oInstance = Activator.CreateInstance(type);
        MethodInfo show2 = type.GetMethod("Show2");
        show2.Invoke(oInstance, new object[] { 123 
        MethodInfo show31 = type.GetMethod("Show3", new Type[] { typeof(string), typeof(int) });
        show31.Invoke(oInstance, new object[] { "细雨浮萍", 234 
        MethodInfo show32 = type.GetMethod("Show3", new Type[] { typeof(int) });
        show32.Invoke(oInstance, new object[] { 345 
        MethodInfo show33 = type.GetMethod("Show3", new Type[] { typeof(string) });
        show33.Invoke(oInstance, new object[] { "幸福靓装" 
        MethodInfo show34 = type.GetMethod("Show3", new Type[0]);
        show34.Invoke(oInstance, null);
    
    //c. 调用私有方法,在获取方法的时候,加上参数BindingFlags.NonPublic | BindingFlags.Instance 
    {
        Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");
        Type type = assembly.GetType("Business.DB.SqlServer.ReflectionTest");
        object oInstance = Activator.CreateInstance(type);
        MethodInfo show4 = type.GetMethod("Show4", BindingFlags.NonPublic | BindingFlags.Instance);
        show4.Invoke(oInstance, new object[] { "String" });
    }
    {
        ReflectionTest.Show5();
        Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");
        Type type = assembly.GetType("Business.DB.SqlServer.ReflectionTest");
        object oInstance = Activator.CreateInstance(type);
        MethodInfo show5 = type.GetMethod("Show5");
        show5.Invoke(null, new object[] { "String" });
        show5.Invoke(oInstance, new object[] { "String" });
    
    //d. 调用泛型方法: 1. 获取到方法后,先确定类型,严格按照参数类型传递参数就可以正常调用
    {
        //泛型是延迟声明,调用的时候,确定类型
        {
            GenericMethod genericMethod = new GenericMethod();
            genericMethod.Show<string, int, DateTime>("", 23, DateTime.Now);
        }
        {
            Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");
            Type type = assembly.GetType("Business.DB.SqlServer.GenericMethod");
            object oInstance = Activator.CreateInstance(type);
            MethodInfo show = type.GetMethod("Show");
            //在执行之前选哟确定是什么类型; 
            MethodInfo genericshow = show.MakeGenericMethod(new Type[] { typeof(int), typeof(string), typeof(DateTime) });
            genericshow.Invoke(oInstance, new object[] { 123, "暖风昔人", DateTime.Now });
            genericshow.Invoke(oInstance, new object[] { "暖风昔人", 123, DateTime.Now 
            //show.Invoke(); //到到底给什么类型呢? 泛型,其实不确定的类型的;
        }
    
            Console.WriteLine(typeof(GenericClass<,,>));
            Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");
            Type type = assembly.GetType("Business.DB.SqlServer.GenericClass`3");
            Type generType = type.MakeGenericType(new Type[] { typeof(int), typeof(string), typeof(DateTime) });
            object oInstance = Activator.CreateInstance(generType);
            MethodInfo show = generType.GetMethod("Show");
            show.Invoke(oInstance, new object[] { 123, "赤", DateTime.Now });
        }
        {
            Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");
            Type type = assembly.GetType("Business.DB.SqlServer.GenericDouble`1");
            Type generType = type.MakeGenericType(new Type[] { typeof(int) });
            object oInstance = Activator.CreateInstance(generType);
            MethodInfo show = generType.GetMethod("Show
            MethodInfo genericMethod = show.MakeGenericMethod(new Type[] { typeof(string), typeof(DateTime) });
            genericMethod.Invoke(oInstance, new object[] { 123, "鱼儿", DateTime.Now });
        }
    }
    

    反射多种应用场景

    反射的局限---真的有性能问题---主要损耗性能的是加载dll 的时候会损耗性能

    //1.有局限---性能问题
    //2.测试用例:普通方式循环100000次创建对象+方法调用:  17毫秒
    //          反射方式循环100000次创建对象+方法调用:  6300毫秒---6秒的
    //3.第二次执行:普通方式:15毫秒   反射方式:6539毫秒
    //4.确实有性能问题:能优化一下?---把动态加载Dll 部分 缓存起来了;每次直接使用加载的dll
    //          执行结果:普通方式:18面试   反射方式:71毫秒了
    //使用反射的建议:1.反射确实有性能问题,2.需要理性对待,就不用吗?当然要用;因为反射的经过优化之后其实性能差也没有差多少的;因为反射能量确实是太多了,大家以后在工作中,可以放心使用; 
    Monitor.Show();
    
    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 < 1000_000; i++) //1000000000
                {
                    IDBHelper iDBHelper = new SqlServerHelper();
                    iDBHelper.Query();
                }
                watch.Stop();
                commonTime = watch.ElapsedMilliseconds;
            }
            {
                Stopwatch watch = new Stopwatch();
                watch.Start();
                Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");//1 动态加载
                Type dbHelperType = assembly.GetType("Business.DB.SqlServer.SqlServerHelper");//2 获取类型  
                for (int i = 0; i < 1000_000; i++)
                {
                    //Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");//1 动态加载
                    //Type dbHelperType = assembly.GetType("Business.DB.SqlServer.SqlServerHelper");//2 获取类型  
                    object oDBHelper = Activator.CreateInstance(dbHelperType);//3 创建对象
                    IDBHelper dbHelper = (IDBHelper)oDBHelper;//4 接口强制转换
                    dbHelper.Query();//5 方法调用
                }
                watch.Stop();
                reflectionTime = watch.ElapsedMilliseconds;
            }
    
            Console.WriteLine($"commonTime={commonTime} reflectionTime={reflectionTime}");
        }
    }
    

    反射调用字段属性--一个类的内部,除了构造函数。方法----还有其他的很多东西;属性字段

    //1.普通方法调用属性字段---简单快捷
    //2.反射操作---稍微麻烦点
    //3.让我们的程序更加稳定---
    //4.如果说People增加一个字段呢?增加一个属性呢?--普通方法就必须要修改代码---重新编译发布----不稳定 
    //6.反射设置值:好像没啥优势
    //7.反射取值:不需要修改代码---代码就更加稳定
    //传统方式使用属性和字段
    {
        Console.WriteLine("***********赋值*************");
        People people = new People();
        people.Id = 134;
        people.Name = "陈大宝";
        people.Age = 25;
        people.Description = "高级班的VIP学员";
        people.Sex = 1;
        //People people1 = new People()
        //{
        //    Id = 134,
        //    Name = "陈大宝",
        //    Age = 25,
        //    Description = "高级班的VIP学员"
        //}; 
        Console.WriteLine("***********取值*************");
        Console.WriteLine($"people.Id={people.Id}");
        Console.WriteLine($"people.Name={people.Name}");
        Console.WriteLine($"people.Age={people.Age}");
        Console.WriteLine($"people.Sex={people.Sex}");
        Console.WriteLine($"people.Description={people.Description}");
    }
    Console.WriteLine("***********反射方式*************");
    //反射呢?如何给属性字段设置值和取值? 
    {
        Type type = typeof(People);
        object pObject = Activator.CreateInstance(type);
        //pObject.Id=234; 
        foreach (var prop in type.GetProperties())
        {
            //Console.WriteLine(prop.Name);
            //逐个属性赋值
            if (prop.Name.Equals("Id"))
            {
                prop.SetValue(pObject, 134);
            }
            else if (prop.Name.Equals("Name"))
            {
                prop.SetValue(pObject, "陈大宝");
            }
            else if (prop.Name.Equals("Age"))
            {
                prop.SetValue(pObject, 25);
            }
            //else if (prop.Name.Equals("Age"))
            //{
            //    prop.SetValue(pObject, 25);
            //}
        }
    
        //SetValue:设置值
        //GetValue:获取值
    
        type.GetProperties();//属性
        type.GetFields();//字段
        foreach (var prop in type.GetProperties())
        {
            Console.WriteLine($"people.{prop.Name}={prop.GetValue(pObject)}");
            //if (prop.Name.Equals("Id"))
            //{
            //    prop.GetValue(pObject);
            //}
            //else if (prop.Name.Equals("Name"))
            //{
            //    prop.GetValue(pObject);
            //}
            //else if (prop.Name.Equals("Age"))
            //{
            //    prop.GetValue(pObject);
            //   }
        }
    }
    

    Emit技术:在运行时去动态的生成Dll、Exe包括dll内部的方法、属性、字段...

    public class ReflectionEmit
    {
        public static void Show()
        {
            // AssemblyBuilder// 建造者模式---创建Assembly
    
            //AssemblyName assemblyName = new AssemblyName("DynamicAssemblyExample");
    
            AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("DynamicAssemblyExample"), AssemblyBuilderAccess.RunAndCollect);
    
            // 对于单个模块程序集,模块名称通常为;程序集名称加上扩展名。  
            ModuleBuilder modulebuilder = assemblyBuilder.DefineDynamicModule("MyModal"); //托管模块
            TypeBuilder typebuilder = modulebuilder.DefineType("MyDynamicType", TypeAttributes.Public);
    
            //Type type= typebuilder.CreateType();
    
            // 在Type中生成私有字段
            FieldBuilder fieldBuilder = typebuilder.DefineField("NumberField", typeof(int), FieldAttributes.Public);
    
            // 定义一个接受整数参数的构造函数,储存在私人区域。  
            Type[] parameterTypes = { typeof(int) };
            ConstructorBuilder ctor1 = typebuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, parameterTypes);
    
            //中间语言的生成者
            ILGenerator ctor1IL = ctor1.GetILGenerator();
    
            //对于构造函数,参数0是对新 
            //实例。在调用base之前将其推到堆栈上 
            //类构造函数。指定的默认构造函数 
            //通过传递 
            //类型(Type.EmptyTypes)到GetConstructor。 
    
            ctor1IL.Emit(OpCodes.Ldarg_0);
            ctor1IL.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
    
            //在推送参数之前,先将实例推送到堆栈上 
            //将被分配给私有字段m\u编号。 
            ctor1IL.Emit(OpCodes.Ldarg_0);
            ctor1IL.Emit(OpCodes.Ldarg_1);
            ctor1IL.Emit(OpCodes.Stfld, fieldBuilder);
            ctor1IL.Emit(OpCodes.Ret);
    
            //完成构造函数传值, Int 设置给字段--测试代码
            {
                //MyDynamicType myDynamicType = new MyDynamicType(123456);
                //int number = myDynamicType.NumberField;
    
                //// 动态的生成程序集;
                //// 动态的生成类;
                //// 动态的生成字段;
                //// 动态的生成构造函数;
                //Type type1 = typebuilder.CreateType();
                //object oInstacne = Activator.CreateInstance(type1, new object[] { 123456 });
                //FieldInfo fieldInfo = type1.GetField("NumberField");
                //object numberFieldResult = fieldInfo.GetValue(oInstacne);
            }
    
            MethodBuilder consoleMethod = typebuilder.DefineMethod("ConsoleMethod", MethodAttributes.Public | MethodAttributes.Static, null, null);
    
            ILGenerator consoleMethodIL = consoleMethod.GetILGenerator();
            consoleMethodIL.Emit(OpCodes.Ldstr, "欢迎来到高级班第15期进阶学习");
            consoleMethodIL.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
            consoleMethodIL.Emit(OpCodes.Ret); //写IL最后一定要Ret
    
            {
                Console.WriteLine("测试。。。。。。");
                Type type1 = typebuilder.CreateType();
                object oInstacne = Activator.CreateInstance(type1, new object[] { 123456 });
                MethodInfo myMethod = type1.GetMethod("ConsoleMethod");
                object oResult = myMethod.Invoke(oInstacne, null);
    
            } 
            MethodBuilder AddMethod = typebuilder.DefineMethod("AddMethod", MethodAttributes.Public | MethodAttributes.Static, typeof(int), new Type[] { typeof(int), typeof(int) });
            ILGenerator AddMethodIL = AddMethod.GetILGenerator();
            AddMethodIL.Emit(OpCodes.Ldarg_0);
            AddMethodIL.Emit(OpCodes.Ldarg_1);
            AddMethodIL.Emit(OpCodes.Add_Ovf_Un);
            AddMethodIL.Emit(OpCodes.Ret);
            {
                //Console.WriteLine("测试。。。。。。");
                //Type type1 = typebuilder.CreateType();
                //object oInstacne = Activator.CreateInstance(type1, new object[] { 123456 });
                //MethodInfo myMethod = type1.GetMethod("AddMethod");
                //object oResult = myMethod.Invoke(oInstacne, new object[] { 12, 34 }); 
            }
        }
    }