反射
大约 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 }); } } }