• 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:CHTKZTSolution1Ant.DB.SQLServerinDebug
    et5.0Ant.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对象技术的一种补充

  • 相关阅读:
    Lc617_合并二叉树
    Lc257_二叉树的所有路径
    Lc222_完全二叉树的节点个数
    记github下载上传遇到的各种问题
    Lc101_对称二叉树
    Lc222_翻转二叉树
    二叉树的dfs 与 bfs (递归遍历)
    全球最火的程序员学习路线!没有之一!3天就在Github收获了接近1w点赞
    大二逃课总结的1.2w字的计算机网络知识!扫盲!
    「IDEA插件精选」安利一个IDEA骚操作:一键生成方法的序列图
  • 原文地址:https://www.cnblogs.com/zmztya/p/14612959.html
Copyright © 2020-2023  润新知