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对象技术的一种补充

 

posted @ 2021-04-03 00:46  zmztyas  阅读(193)  评论(0编辑  收藏  举报