c#进阶 之 反射Reflection
学习课件资料:https://www.bilibili.com/video/BV1J54y1B74C?p=26
exe/dll(主要区别:exe有文件入口) --- metadata(元数据:描述exe/dll文件的一个数据清单)----反射(Reflection)用来操作获取元数据
注:clr/jit也需要读取到metadata,那么就需要用到反射
[1]更新程序时 (更新自己的dll)
[2]使用别人的dll文件(这种可以读取别人私有的东西)
在下面的代码中,理解英文单词会更容易记忆语法
Assembly:编译
LoadFrom: 加载 dll文件/路径
Type:类 找到dll中的class
MakeGenericType:构造未注册的类型 ()设置类(class)的参数类型
Activator : 激活
CreateInstance: 创建实例 (实例化类)
MakeGenericMethod:构造未注册的方法 (设置方法的参数类型)
反射是什么?
就是一个操作元数据的类库(可以把反射当成一个小工具,用来读取或者操作元数据的,类,方法,特性,属性字段(为什么要通过反射间接去操作,因为我们需要动态,读取私有的对象)
2.哪些地方使用到了?asp.net MVC ----ORM---LOC---AOP 几乎所有裤架都会使用反射
3.通过反射加载dll文件
引用:using System.Reflection;
1.反射加载dll文件
using System; using System.Reflection; //引入 namespace KZT { class Program { static void Main(string[] args) { //需要引入后才能读取 Assembly assembly = Assembly.Load("Ant.DB.SQLServer"); //直接根据地址进行读取 Assembly assemblyFile = Assembly.LoadFile(@"D:\CHT\KZT\Solution1\Ant.DB.SQLServer\bin\Debug\net5.0\Ant.DB.SQLServer.dll"); //可以写dll文件名也可以写地址 Assembly assemblyFrom = Assembly.LoadFrom("Ant.DB.SQLServer"); //读取有哪些类 foreach (var item in assembly.GetTypes()) { //输出类名 Console.WriteLine(item.Name); //读取类里面有哪些方法 foreach (var method in item.GetMethods()) { Console.WriteLine("这是方法:"+ method); } } } } }
2.通过反射创建对象
#region 使用反射创建对象
//注意:Person 是一个类库的类,IPerson是接口类库的接口,然后Person 继承 IPerson
Assembly assembly = Assembly.Load("Ant.DB.SQLServer");//读取dll Type type = assembly.GetType("Ant.DB.SQLServer.Person"); //获取类 Object oPerson = Activator.CreateInstance(type); // 创建对象 //Person p = new Person(); IPerson person = oPerson as IPerson; //类型转换(as 转换不报错,类型不对就返回null) var name = person.GetName(); Console.WriteLine(name); #endregion
3.使用反射创建对象 (带参数<构造函数>)
#region 使用反射创建对象(带参数的构造函数) Assembly assembly = Assembly.LoadFrom("Ant.DB.SQLServer.dll"); Type type = assembly.GetType("Ant.DB.SQLServer.Student"); //获取到这个类型下面所有的构造方法 foreach (ConstructorInfo ctor in type.GetConstructors()) //获取到所有的构造方法 { Console.WriteLine(ctor.Name); foreach (var parameter in ctor.GetParameters()) //获取到构造方法的所有参数类型 { Console.WriteLine(parameter.ParameterType); } } //object oStu = Activator.CreateInstance(type);//无参数构造函数 Object oStu = Activator.CreateInstance(type, new Object[] { "张三", 18 }); //有参数的构造函数 IPerson p = oStu as IPerson; Console.WriteLine(p.GetName()); #endregion
4.使用反射创建对象(私有构造函数)
#region 使用反射创建对象(私有构造函数) //Teacher tea = new Teacher(); //teacher类中有一个私有的构造函数,报错 Assembly assembly = Assembly.LoadFrom("Ant.DB.SQLServer.dll"); Type type = assembly.GetType("Ant.DB.SQLServer.Teacher"); object oTeacher = Activator.CreateInstance(type,true);//这里的true 就是可以使用私有构造函数 IPerson oTea = oTeacher as IPerson; oTea.GetName();
5.使用反射创建泛型类
#region 使用反射创建泛型 Assembly assembly = Assembly.LoadFrom("Ant.DB.SQLServer.dll"); //读取dll Type type = assembly.GetType("Ant.DB.SQLServer.Generic`3");//获取类 //这里的 " `3 " 表示占位符,有3个占位符 var makeType = type.MakeGenericType(new Type[] { typeof(int),typeof(string),typeof(double)}); object oGen = Activator.CreateInstance(makeType);//创建泛型类 #endregion
6.通过反射调用方法(第2点知识也是可以实现的)
#region 使用反射调用方法 Assembly assembly = Assembly.LoadFrom("Ant.DB.SQLServer.dll"); Type type = assembly.GetType("Ant.DB.SQLServer.MyMethod"); object oMyMethod = Activator.CreateInstance(type); foreach (var method in type.GetMethods()) //遍历方法 { Console.WriteLine(method.Name); foreach (var parameter in method.GetParameters()) //遍历方法参数类型 { Console.WriteLine(parameter.Name + " "+ parameter.ParameterType); } } { //无参数 MethodInfo methodInfo = type.GetMethod("GetName"); methodInfo.Invoke(oMyMethod, null); //调用方法 } { //有参数以下都可以 //MethodInfo methodInfo = type.GetMethod("GetAge"); //或者是 MethodInfo methodInfo = type.GetMethod("GetAge",new Type[] { typeof(int)}); methodInfo.Invoke(oMyMethod, new object[] {123 }); //调用方法 } { //静态方法 MethodInfo methodInfo = type.GetMethod("GetAddress", new Type[] { typeof(string) }); methodInfo.Invoke(oMyMethod, new object[] { "中国" }); //调用方法 } #endregion
7.通过反射调用私有方法
#region 使用反射调用私有方法 Assembly assembly = Assembly.LoadFrom("Ant.DB.SQLServer.dll"); Type type = assembly.GetType("Ant.DB.SQLServer.Parent"); object oParent = Activator.CreateInstance(type); { MethodInfo methodInfo = type.GetMethod("WriteName", BindingFlags.Instance | BindingFlags.NonPublic); methodInfo.Invoke(oParent, null); } { MethodInfo methodInfo = type.GetMethod("WriteAge", BindingFlags.Instance | BindingFlags.NonPublic); methodInfo.Invoke(oParent, new object[] { 123 }); } #endregion
8.通过反射调用泛型方法(普通类里面的泛型方法调用)
#region 通过反射调用泛型方法 Assembly assembly = Assembly.LoadFrom("Ant.DB.SQLServer.dll"); //读取dll Type type = assembly.GetType("Ant.DB.SQLServer.Gen");//获取类 //这里的 " `3 " 表示占位符,有3个占位符 object oGen = Activator.CreateInstance(type);//实例化类型 MethodInfo methodInfo = type.GetMethod("Get");//找到要调用的方法 var methodGeneric = methodInfo.MakeGenericMethod(new Type[] { typeof(int), typeof(string), typeof(int) }); methodGeneric.Invoke(oGen, new object[] { 1, "展示那", 2 }); #endregion
9.通过泛型类里的泛型方法调用
#region 通过反射调用泛型类里的泛型方法调用 Assembly assembly = Assembly.LoadFrom("Ant.DB.SQLServer.dll");//读取 Type type = assembly.GetType("Ant.DB.SQLServer.Generic`3"); //获取类 //这里的 " `3 " 表示占位符,有3个占位符 var makeType = type.MakeGenericType(new Type[] { typeof(int), typeof(string), typeof(DateTime) }); object oGeneric = Activator.CreateInstance(makeType);//创建泛型类 MethodInfo methodInfo = makeType.GetMethod("Write"); var methodGeneric = methodInfo.MakeGenericMethod(new Type[] { typeof(int), typeof(string), typeof(DateTime) }); methodGeneric.Invoke(oGeneric, new object[] { 11, "22", new DateTime() }); #endregion
10.通过反射操作字段和属性等成员
#region 通过反射操作字段和属性等成员 Person person = new Person() { Id = 1, Name = "zs", Address = "背景" }; Assembly assembly = Assembly.LoadFrom("Ant.DB.SQLServer.dll"); Type type = assembly.GetType("Ant.DB.SQLServer.Person"); object oPerson = Activator.CreateInstance(type); //方式一 foreach (var prop in type.GetProperties()) { Console.WriteLine($"{prop.PropertyType} + {prop.Name}"); //获取属性类型和名称 if (prop.Name.Equals("Id")) { prop.SetValue(person, 2); } } Console.WriteLine(person.Id); //方式二 PropertyInfo[] propertyInfos = type.GetProperties();//查找所有的属性 PropertyInfo propertyInfo = type.GetProperty("Id"); propertyInfo.SetValue(person, 5); #endregion
扩展内容:
反射 与 MVC和AOP(了解)
//dll文件名称 + 类型名称 + 方法名称 (可以拿到方法)
//mvc方式: https://localhost:端口/Home/index 就相当于 主机 + 控制器 + 方法 说是路由,但本质还是反射
//反射在mvc有一些缺陷
(1)在mvc中是不允许有相同的方法名的,所以通过标识符来识别
什么是AOP?他是一种面向切面编程,是oop对象技术的一种补充