C# 反射
C#编译过程:
C#语言——>编译器编译——>DLL/EXE(metadate元数据、IL中间语言)(确定具体类型)——>CLR/JIT——>机器码01010101——>电脑
EXE/DLL的主要区别在于是否有Main函数入口
metadata元数据:描述EXE/DLL文件的一个数据清单
JIT通过访问元数据确定具体类型后,才会继续编译为机器码
反射用来操作获取元数据(matedata)
反射是什么:
反射就是一个操作metadata的一个类库(可以把反射当成一个小工具用来读取或者操作元数据)操作 类、方法、特性、属性字段。
为什么要通过反射间接去操作:
- 因为我们需要动态
- 读取私有的对象
{
- 更新程序时(更新自己的DLL)
- 使用别人的DLL文件(这种可以读取别人的私有的东西)
}
使用到反射的地方:
asp.net MVC ---ORM ---LOC ---AOP 几乎所有的框架都会使用反射
通过反射加载DLL文件
加载方式一:通过DLL文件名进行加载
需要将文件添加到项目引用 才能够进行使用否则使用完全路径
Assembly assembly = Assembly.Load("DLL文件名");
foreach(var it in assembly.GetTypes())//返回工程下所有的类
{
Console.WriteLine(it.Name);
foreach(var fun in it.GetMethods) //返回所有方法的名称
{
Console.WriteLine("这是"+fun.Name+"方法");
}
}
加载方式二:完整路径(详细路径)
Assembly assembly = Assembly.LoadFile("@完整路径");
加载方式三:完全限定名
Assembly assembly = LoadForm("DLL文件名加上拓展名");
Assembly assembly = LoadForm("@完整路径");
使用反射创建对象
Assembly assembly = Assembly.LoadForm("DLL文件名加上拓展名");//加载DLL文件
Type type = assembly.GetType("命名空间.类名");//获取类型(需要完整的类型名称)
object oDbHelper = Activator.CreateInstance(type);//创建对象 不确定类型定义object装箱使用
//相当于new一个对象
//创建父类对象用来接受odject对象的转换 然后调用自身方法
使用反射创建带参数对象
//通过反射读取DLL元数据
Assembly assembly = Assembly.LoadForm("DLL文件名+后缀名");
//加载类型
Type type = assembly.GetType("命名空间.类名");
{
//获取到这个类型下面所有的构造方法
foreach(ConstructorInfo cotor in type.GetConstructors())//获取到所有的构造方法
{
Console.WriteLine(ctor.Name);
foreach(var parameter in ctor.GetParameters())//获取到构造方法的所有参数类型
{
Console.WriteLine(parameter.ParameterType);//显示类型名称
}
}
}
//创建带带参数对象
object Ocotr = Activator.CreateInstance(type,new object[]{传入参数});
使用反射创建对象(私有构造函数)
通过这种方式也可以破坏单例
Assembly assemby = Assembly.LoadFrom("DLL文件名+后缀名");
Type type = assembly.GetType("命名空间.类名");
//创建私有构造函数对象
object oPrivate = Activator.Createlnstance(type,true); //后一个参数确定构造是否为私有
使用反射创建泛型类
Assembly assembly = Assembly.LoadFrom("DLL文件名+后缀名");
Type type = assembly.GetType("命名空间.类名+`+类型个数");//需要在末尾加上反单引号和类型个数进行占位
Type makeType = type.MakeGenericType(new Type[]{typeof(int),typeof(string),typeof(double)});//在数组内传入需要的类型
object oGeneric = Active.CreateInstance(makeType);
使用反射调用方法
Assembky assembly = Assembly.LoadFrom("DLL文件名+后缀名");
Type type = assembly.GetType("命名空间.类名");
object oReflection = 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("方法名");
methodInfo.Invoke(oReflection,null); //调用方法
//调用有参方法
MethodInfo methodInfo = type.GetMethod("方法名");
methodInfo.Invoke(oReflection,new object[]{传入参数});
//调用重载方法
//获取方法时 给到对应参数类型
MethodInfo methodInfo = type.GetMethod("方法名",new Type[]{typeof(类型)}...);
methodInfo.Invoke(oReflection,new object[]{传入对应类型参数});
//无参数重载
MethodInfo methodInfo = type.GetMethod("方法名",new Type[]{});
methodInfo.Invoke(oReflection,null);
//静态方法的调用
MethodInfo methodInfo = type.GetMethod("方法名");
methodInfo.Invoke(oReflection,new object[]{传入参数});//调用方法
{
//另一种调用方法
MethodInfo methodInfo = type.GetMethod("方法名");
methodInfo.Invoke(null,new object[]{传入参数});
}
使用反射调用私有方法
需要在获取方法的时候添加BindingFlags.Instance|BinDingFlags.NonPubliction两个参数 来说明此方法为实例非公开的方法
Assembky assembly = Assembly.LoadFrom("DLL文件名+后缀名");
Type type = assembly.GetType("命名空间.类名");
object oReflection = 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("方法名",BindingFlags.Instance|BindingFlags.NonPublic);
methodInfo.Invoke(oReflection,new object[]{参数});
使用反射调用普通类里泛型方法
Assembky assembly = Assembly.LoadFrom("DLL文件名+后缀名");
Type type = assembly.GetType("命名空间.类名");
object oReflection = Activator.CreateInstance(type);
//获取要调用的方法
MethodInfo methodInfo = type.GetMethod("Test");
//确定方法的参数类型和个数
MethodInfo methodGeneric = methodInfo.MakeGenericMethod(new Type[]{typeof(int),typeof(string),typeof(double)});
//调用方法
methodGeneric.Invoke(oReflection,new object[]{传入对应类型的参数});
使用反射调用泛型类当中的泛型方法
Assembky assembly = Assembly.LoadFrom("DLL文件名+后缀名");
Type type = assembly.GetType("命名空间.类名+`+类型个数");
//确定泛型的参数类型
Type typeNew = type.MakeGenericType(new Type[]{typeof(参数类型)...});
object oReflection = Activator.CreateInstance(type);
//获取调用方法
MethodInfo methodInfo = type.GetMethod("方法名");
//确定方法的参数类型
MethodInfo methodInfoNew = methodInfo.MakeGenericMethod(new Type[]{typeof(参数类型)...});
methodInfoNew.Invoke(oReflection,new object[]{传入对应类型参数});
使用反射操作属性和字段等成员
Assembly assembly = Assembly.LoadForm("DLL文件名+后缀名");
Type type = assembly.Gettype("命名空间+类名");
object oStudent = Activator.Createlnstance(type);//创建对象
//方式一
foreach(var prop in type.GetProperties())
{
//获取属性的类型 名字 数值
Console.WriteLine($"{prop.PropertyType}+{prop.Name}={prop.GetValue(类对象)}");
if(prop.Name.Equals("属性名"))
{
prop.SetValue(对象,设置的参数);
}
}
//方式二
//使用PropertyInfo
PropertyInfo[] propertyInfos = type.GetProperties();//查找所有属性
PropertyInfo propertyInfo = type.GetProperty("属性名");
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!