C#-反射

一、概念

  1. 反射(Reflection)在C#中是一种非常重要的特性,它为开发者提供了在运行时获取和操作关于类型、成员、属性、方法等的详细信息的能力。通过反射,开发者可以在程序运行期间动态地创建对象、调用方法、设置属性值以及进行其他多种操作,而不需要事先在代码中硬编码这些操作。
  2. C#中的反射API主要集中在System.Reflection命名空间下,该命名空间包含了多个用于反射的类和接口。

1.1常用的反射类型:

  1. Assembly(程序集):Assembly类用于表示一个程序集,可以加载和卸载程序集,以及获取程序集中的类型、资源等信息。
  2. Type(类型):Type类表示程序集中的任意类型,可以是类、接口、枚举、结构等。通过Type类可以获取类型的成员信息,如方法和属性等。
  3. MethodInfo(方法信息):MethodInfo类提供了关于特定方法的信息,包括方法的名称、参数、返回类型等,还可以调用该方法。
  4. PropertyInfo(属性信息):PropertyInfo类用于表示属性,可以获取或设置属性的值。
  5. FieldInfo(字段信息):FieldInfo类用于表示字段,可以获取或设置字段的值。

1.2常用场景

  1. 动态加载程序集:在运行时根据需要加载.dll或.exe文件,并访问其中的类型和成员。
  2. 晚期绑定和早期绑定:晚期绑定是指在程序运行时才确定要调用的方法或访问的属性,而早期绑定是在编译时就确定。反射可以实现晚期绑定。
  3. 对象序列化和反序列化:在序列化和反序列化过程中,反射可以动态地读取和写入对象的各个属性。
  4. 实现插件系统:通过反射可以加载和调用插件中的功能,而无需预先知道插件的具体实现细节。
  5. 单元测试和ORM(对象关系映射)技术:在单元测试中,反射可用于动态调用待测试的方法;在ORM技术中,反射则可用于动态访问和映射对象的属性至数据库表的列。

1.3程序集概念

  1. 程序集(Assembly)是.NET框架下代码编译的一个逻辑单元,用于组合相关的代码和类型,最终生成PE文件
  2. 程序集是.NET应用程序的基本组成单元,它以可执行文件(.exe)动态链接库文件(.dll)的形式存在。一个程序集可以包含一个或多个模块,每个模块又可以包括多个类型(如类、接口、枚举等)。程序集不仅包含编译后的IL(中间语言)代码,还包含描述程序集自身的元数据、资源文件等信息。
  3. 在软件开发过程中,一个项目通常对应一个程序集。例如,在Visual Studio中,一个解决方案可以包含多个项目,每个项目编译后都会生成一个程序集(一般是一个.dll文件)。这些程序集可以被其他项目引用,从而实现功能的复用和模块化开发。

二、Type类

2.1、概念

Type类是C#反射中的一个核心类,用于表示所有.NET类型的公共基类。通过Type类,可以访问类型的元数据,获取类型的成员信息,并进行实例化等操作。以下将详细探讨Type类的各个方面:
定义:Type类位于System.Reflection命名空间下,它提供了很多方法来获取类型信息、创建实例、执行方法等。

2.2、功能

通过Type类,可以检查类型是否为泛型类型、接口、委托等。同时,还可以获取类型的属性、方法、事件等成员信息。

2.3、使用

  1. 获取Type实例
    静态方法:可以使用Type的静态方法如GetType、GetTypes等来获取类型信息。例如,typeof(int)返回表示int类型的Type对象。
    动态实例:通过对象实例调用GetType()方法获取其类型。例如,一个字符串实例myString.GetType()将返回String类型的Type对象。
  2. 获取类型信息
    属性和方法:使用Type对象的GetProperties和GetMethods方法可以分别获取类型的所有属性和方法。这些返回的PropertyInfo和MethodInfo对象提供了更详细的成员信息。
    基类和接口:可以通过Type对象的BaseType属性获取其基类的类型,IsClass属性判断是否为类,Implements接口方法检查实现的接口。
  3. 创建类型实例
    使用Activator类:Activator类提供了基于Type创建实例的方法,如CreateInstance。这允许在运行时动态创建对象。
    使用ConstructorInfo:通过Type对象的GetConstructors方法获取构造函数,然后使用ConstructorInfo对象的Invoke方法创建实例。
  4. 调用类型方法
    MethodInfo对象:通过Type对象的GetMethods获取方法列表,然后用MethodInfo对象的Invoke方法动态调用这些方法。
    参数处理:MethodInfo的Invoke方法需要参数数组。如果方法需要的参数类型与传递的参数类型不匹配,需要进行适当的类型转换。
  5. 类型的兼容性和转换
    类型兼容检查:IsAssignableFrom方法可以用来检查一个类型是否可以从另一个类型派生。例如,typeof(object).IsAssignableFrom(typeof(string))将返回true。
    类型转换:Type类提供了几个方法来检查和执行类型转换,如IsInstanceOfType方法和ChangeType方法。

2.4、代码实例

// See https://aka.ms/new-console-template for more information
//Console.WriteLine("Hello, World!");
//反射
//Type类实例化

using System.Reflection;

Type type = typeof(Person);
Console.WriteLine("--------------------获取属性信息------------------------------");
Console.WriteLine(type.ToString());
//01、获取类中属性信息GetProperties(),返回的是PropertyInfo[]类型数组
PropertyInfo[] propertyInfos=type.GetProperties();
foreach (var item in propertyInfos)
{
    Console.WriteLine(item.Name);
    Console.WriteLine(item.Attributes);//还有其他特性可以获取
}
Console.WriteLine("-----------------------获取字段信息---------------------------");

//02、获取所有字段,只能获取共有字段,属性的第二种定义方式也属于私有字段
FieldInfo[] fieldInfos=type.GetFields();
foreach (var field in fieldInfos) { 

    Console.WriteLine(field.Name);
    Console.WriteLine(field.FieldType);
}

/*结果:
iD
System.Int32
name
System.String*/

Console.WriteLine("-----------------------获取类的信息---------------------------");
//直接使用type调用相关方法
Console.WriteLine(type.Name);
Console.WriteLine(type.Attributes);

Console.WriteLine("-----------------------获取构造方法的信息---------------------------");
ConstructorInfo[] methodInfo =type.GetConstructors();
foreach (var item in methodInfo)
{
    Console.WriteLine(item);//返回的是构造方法的签名,返回值与参数
}
/* 
Void.ctor()
Void.ctor(Int32, System.String)*/
Console.WriteLine("-----------------------获取方法的信息---------------------------");
MethodInfo[] info = type.GetMethods();

foreach (var item in info)
{
    Console.WriteLine(item.Name);
}



/// <summary>
/// 定义反射测试类
/// </summary>
class  Person{

    //01、定义公有字段
    public int iD;
    public string name;
    //02、定义私有字段
    private string Sex;
    //03、定义属性,属性有两种定义方式
    //方式1
    public int Age { get; set; }
    //方式2
    private string address;
    //04无参构造
    public Person()
    {
        Console.WriteLine("无参构造");
    }
    //05有参构造
    public Person(int iD, string name)
    {
        this.iD = iD;
        this.name = name;
    }
    public string Address { 
        get { return this.address; }   
        set { this.address = value; }
    }
}

三、Assembly类

3.1概念及使用

Assembly类在C#反射中是用于操作程序集的一个重要工具,它能够加载、枚举、和操纵程序集。以下是对Assembly类的详细解析:

  1. 加载程序集
    • 静态加载方法:Assembly.Load方法可以加载一个程序集,通常用于加载同一目录下或全局程序集中的其它程序集[1]。例如,Assembly assembly = Assembly.Load("AssemblyName");
    • 动态加载方法:Assembly.LoadFrom和Assembly.LoadFile方法可以指定文件路径来加载程序集。例如,Assembly assembly = Assembly.LoadFrom("包含程序集清单的文件的名称或路径");[2]。
  2. 枚举程序集中的类型
    • 获取类型信息:通过Assembly实例的GetTypes方法可以得到程序集中定义的所有类型的Type对象数组[3]。例如,Type[] types = assembly.GetTypes();
    • 创建类型实例:结合Activator.CreateInstance方法,可以用枚举到的Type动态创建类型的实例。例如,object obj = Activator.CreateInstance(type);[4]。
  3. 调用方法与访问属性
    • 调用方法:MethodInfo类可以用于获取方法和动态调用方法。例如,使用MethodInfo method = type.GetMethod("MethodName");来获取方法信息,然后使用method.Invoke(obj, parameters);来调用它[4]。
    • 访问属性:PropertyInfo类可以用来获取属性信息和动态设置或获取属性值。例如,PropertyInfo property = type.GetProperty("PropertyName");用来获取属性信息,然后property.SetValue(obj, value, index);用于设置属性值[4]。
  4. 获取程序集信息
    • 获取程序集名称和版本:Assembly实例的GetName方法可以获取程序集的完整名称、版本等信息。例如,AssemblyName name = assembly.GetName();[4]。
    • 获取程序集元数据:可以使用Assembly实例的其他方法如GetCustomAttributes来检查程序集的特性和元数据[4]。
  5. 操纵程序集
    • 创建新实例:除了加载已存在的程序集外,Assembly类还提供了CreateInstance方法用于创建程序集中特定类型的新实例[3]。例如,object instance = assembly.CreateInstance("TypeName");
    • 获取当前程序集:Assembly.GetExecutingAssembly方法可以获取当前正在执行的程序集,这在需要访问当前程序集中的资源或类型时非常有用[2]。例如,Assembly currentAssembly = Assembly.GetExecutingAssembly();

3.2应用-Assembly拿到成员-Type操作成员

3.2.1、Assembly获取程序集中的类/接口

  1. VS中定义类库文件:demo49反射_数据,作为程序集文件
  2. 定义控制台应用程序:demo49反射_Assembly使用,通过反射 去获取指定程序集里面的程序 操作成员(注意:此文将并没有对程序集文件添加依赖,不可直接操作程序集文件中内容,需要使用反射相关技术获取程序集文件在这里插入图片描述
  3. 通过LoadFile获取程序集文件:通过loadFile+程序集的绝对路径的方式 获取到了要反射的程序集
    在这里插入图片描述
Assembly ass= Assembly.LoadFile(@"E:\c#体系课\04c#高级\代码\demo49反射_数据\bin\Debug\net7.0\demo49反射_数据.dll");

在这里插入图片描述
4. 通过Assembly对象 自己程序的GetType获取程序集中指定的类型 成员 GetType()+类型全名称 [命名空间.类型名字]

//通过GetTypes() 获取程序集中 所以的成员   获取到的是  pubic + internal
Type type = ass.GetType("demo49反射_数据.Person");//获取单个
Type[] types = ass.GetTypes();//获取所有

但是有时候我们并不希望获取内部internal成员

//只获取程序集中被public修饰的成员,不要internal成员  Exported:出口
Type[] types = ass.GetExportedTypes();

foreach (var item in types)
{
    Console.WriteLine(item.Name);
}

在这里插入图片描述
在这里插入图片描述

3.2.2、Type获取类中方法

  1. 添加数据,对Person类中添加需要测试的属性,方法等数据
public class  Person
{
    //01、定义属性
    public string Name { get; set; }
    public int Age { get; set; }
    public char Gender { get; set; }
    //02、定义方法
    public static void SayHello()
    {
        Console.WriteLine("我是静态方法");
    }

    public void Sayhi()
    {
        Console.WriteLine("我是实例方法");
    }

    public int Add(int n1, int n2) {

        return n1 + n2;
    }

    public Person()
    {
        
    }
    //03、有参构造
    public Person(string name,int age,char gender)
    {
        this.Name = name;
        this.Age = age;
        this.Gender = gender;
    }

    public void Test() {
        Console.WriteLine("我是无参方法");
    }

    public void Test(string name) {
        Console.WriteLine(name);
    }

    public void Test(int n1,int n2)
    {
        Console.WriteLine(n1+n2);
    }

}
  1. 获取类中方法
//01、Assembly操作
Assembly ass= Assembly.LoadFile(@"D:\C#_Project\05C#高级代码\demo49反射_数据\bin\Debug\net7.0\demo49反射_数据.dll");

//02、Type操作
Type type = ass.GetType("demo49反射_数据.Person");
//获取所有方法
MethodInfo[] methodInfos = type.GetMethods();
foreach (var item in methodInfos)
{
    Console.WriteLine(item.Name);
}


在这里插入图片描述

添加限定条件,只要静态方法

//如果我们要用BindingFlags.Static这个枚举 需要再加上一个public 枚举进行配合
MethodInfo[] methodInfos = type.GetMethods(BindingFlags.Static | BindingFlags.Public);
foreach (var item in methodInfos)
{
    Console.WriteLine(item.Name);
}

//如果只要其中一个方法就可以用下面这种方式
MethodInfo method = type.GetMethod("SayHello");

在这里插入图片描述

3.2.3、执行获取的方法

如果执行静态方法 注意:不可以像调用委托或者事件一样通过加括号直接调用
间接调用 通过 invoke调用

//第一个参数 在调用成员的是很好 是否需要传入对象
//1.静态方法:类.
//2.实例方法:对象.
//第二个参数 调用方法的时候是否需要传入参数 如果需要就传入参数 不需要传入null就可以了

 method.Invoke(null,null);

在这里插入图片描述

3.2.4、Activator创建对象(方法一)

对象创建唯一途径就是构造方法被调用

//01、获取程序集
Assembly ass= Assembly.LoadFile(@"D:\C#_Project\05C#高级代码\demo49反射_数据\bin\Debug\net7.0\demo49反射_数据.dll");

//02、获取程序集中需要的类
Type type = ass.GetType("demo49反射_数据.Person");

//03、创建person对象实例  在反射中 一般有2中方式创建对象 
//1.调用构造函数
//2.通过Activator 动态创建实例对象
//Activator的底层 就是调用无参构造函数  
object person = Activator.CreateInstance(type);
Console.WriteLine(person.ToString());

//调用实例方法,参数1:实例对象
method.Invoke(person,null);

注意:SayHello是静态方法直接通过类就可获取
在这里插入图片描述

3.2.5、构造方法创建对象(方法二)

//LoadFile传入的路径是绝对路径    不是相对路径
//1.通过loadFile+程序集的绝对路径的方式 获取到了要反射的程序集,从文件中找,不要直接属性复制
Assembly ass= Assembly.LoadFile(@"D:\C#_Project\05C#高级代码\demo49反射_数据\bin\Debug\net7.0\demo49反射_数据.dll");
Type type = ass.GetType("demo49反射_数据.Person");
//获取单个构造函数
//参数:string name,int age,char gender
ConstructorInfo constructor= type.GetConstructor(new Type[] { typeof(string),typeof(int),typeof(char)});
object person= constructor.Invoke(new object[] {"张三",10,'男'});
//间接调用  person返回的就是你创建的对象

PropertyInfo property= type.GetProperty("Name");

//通过GetValue()调用这个方法可以获取属性的值
object propertys= property.GetValue(person);
Console.WriteLine(propertys);//输出:张三

3.2.6、获取有参有返回值方法

//01、获取程序集
Assembly ass= Assembly.LoadFile(@"D:\C#_Project\05C#高级代码\demo49反射_数据\bin\Debug\net7.0\demo49反射_数据.dll");
//02、通过Assembly对象 自己程序的GetType获取程序集中指定的类型 成员  GetType()+类型全名称 [命名空间.类型名字]
Type type = ass.GetType("demo49反射_数据.Person");
//3.1、创建类对象
object person = Activator.CreateInstance(type);
//3.2、通过Type数组 判断调用方法的参数个数和参数类型  依次告诉我们编译器我们想要哪个方法
MethodInfo method = type.GetMethod("Test", new Type[] { });

MethodInfo method1 = type.GetMethod("Test", new Type[] { typeof(string) });

MethodInfo method2= type.GetMethod("Test", new Type[] { typeof(int), typeof(int) });

//04、调用重载方法 编译器无法直接从是否传递的参数来潘顿我们调用的是哪个方法
Console.WriteLine(method.Name);
method.Invoke(person,new object[] { });

Console.WriteLine(method1.Name);
method1.Invoke(person,new object[] {10 });

Console.WriteLine(method2.Name);
method2.Invoke(person,new object[] { 10,20 });

四、反射常用API

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/784085.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【免费数字孪生平台】零代码制作智慧农业蔬菜大棚可视化

一&#xff0e;智慧农业的价值 智慧农业&#xff0c;作为农业中的智慧经济形态&#xff0c;是现代科学技术与农业种植深度融合的产物。它通过将物联网、云计算、大数据、人工智能等现代信息技术集成应用于农业生产中&#xff0c;实现了农业生产的无人化、自动化和智能化管理。…

考CISP,不要踩坑的几点建议

当你立志要在信息安全领域闯出一片天&#xff0c;可能多少都会听行内人说&#xff0c;搞本CISP。但这个认证究竟该怎么拿&#xff1f;需要培训吗&#xff1f;培训又是怎么一回事&#xff1f;价格如何&#xff1f;还有&#xff0c;什么时候开始准备最好&#xff1f;这些问题可能…

为什么看起来很低智商的广告比高大上的广告转化效果更好?

大家在刷抖音的时候&#xff0c;是不是总能刷到一些看起来很低质、很尴尬的广告&#xff0c;或者说是一些毫无吸引力的小说剧情&#xff1f;这些广告和内容让人忍不住怀疑&#xff0c;为什么这么低级的广告竟然会有人点击&#xff1f;其实&#xff0c;这背后有着深刻的营销策略…

BJT的结构(晶体管电压/电流+β+晶体管特性曲线/截止与饱和+直流负载线(Q点))+单片机数码管基础

2024-7-8&#xff0c;星期一&#xff0c;20:23&#xff0c;天气&#xff1a;晴&#xff0c;心情&#xff1a;晴。今天没有什么特殊的事情发生&#xff0c;周末休息了两天&#xff0c;周一回来继续学习啦&#xff0c;加油加油&#xff01;&#xff01;&#xff01; 今日完成模电…

HAProxy安装配置详解

HAProxy是一个使用C语言编写的自由及开放源代码软件&#xff0c;其提供高可用性、负载均衡&#xff0c;以及基于TCP和HTTP的应用程序代理。   HAProxy特别适用于那些负载特大的web站点&#xff0c;这些站点通常又需要会话保持或七层处理。HAProxy运行在当前的硬件上&#xf…

珍藏多年的计算机内核结构大全笔记,掌握计算机工作原理真不难

本篇会加入个人的所谓鱼式疯言 ❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言 而是理解过并总结出来通俗易懂的大白话, 小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的. &#x1f92d;&#x1f92d;&#x1f92d;可能说的不是那么严谨.但小编初心是能让更多人…

大模型面试笔试常见问题汇总(精心准备)

1 GPT和Bert的区别? 1.模型结构和训练方式 BERT通过掩码语言模型(Masked Language Model, MLM)和下一句预测(Next Sentence Prediction, NSP)任务进行训练: 掩码语言模型(MLM):在输入序列中,BERT随机掩盖一些词语,并要求模型预测这些被掩盖的词语。这使得BERT能够学…

TCP的p2p网络模式

TCP的p2p网络模式 1、tcp连接的状态有以下11种 CLOSED&#xff1a;关闭状态LISTEN&#xff1a;服务端状态&#xff0c;等待客户端发起连接请求SYN_SENT&#xff1a;客户端已发送同步连接请求&#xff0c;等待服务端相应SYN_RECEIVED&#xff1a;服务器收到客户端的SYN请请求&…

214.贪心算法:K次取反后最大化的数组和(力扣)

class Solution { public:int largestSumAfterKNegations(vector<int>& nums, int k) {int sum 0;// 进行k次取反操作while (k > 0){// 对数组进行排序sort(nums.begin(), nums.end());// 将最小的元素取反nums[0] -nums[0];// 减少k的值k--;}// 计算数组的总和…

学习数据库2

在数据库中创建一个表student&#xff0c;用于存储学生信息 查看建表结果 向student表中添加一条新记录 记录中id字段的值为1&#xff0c;name字段的值为"monkey"&#xff0c;grade字段的值为98.5 并查看结果 向student表中添加多条新记录 2,"bob"…

水利水库大坝结构安全自动化监测主要测哪些内容?

在大坝安全自动化监测系统建设中&#xff0c;应根据坝型、坝体结构和地质条件等因素选定监测项目&#xff1b;主要监测对象包括坝体、坝基及有关的各种主要水工建筑物、大坝附近的不稳定岸坡和大坝周边的气象环境。深圳安锐科技建议参考下列表格适当调整。 &#xff08;一&am…

预训练对齐:数学理论到工程实践的桥梁

在人工智能和机器学习领域&#xff0c;预训练模型的对齐是一个至关重要的概念。本篇博客源自听了一场黄民烈老师关于大模型对齐的分享&#xff0c;整理内容如下&#xff0c;供大家参考。 数学理论中的预训练对齐 数学理论上&#xff0c;预训练对齐是什么&#xff1f; 序列…

比赛获奖的武林秘籍:04 电子类比赛嵌入式开发快速必看的上手指南

比赛获奖的武林秘籍&#xff1a;04 电子类比赛嵌入式开发快速必看的上手指南 摘要 本文主要介绍了电子类比赛中负责嵌入式开发同学的上手比赛的步骤、开发项目的流程和具体需要学习的内容&#xff0c;并结合自身比赛经历给出了相关建议。 正文 如何开始上手做自己第一个项目…

STM32中的DMA:解锁高效数据传输的秘密武器(内附实例)

目录 引言 理解DMA&#xff1a;数据的高效搬运工 DMA的主要特性 多优先级请求 事件标志 数据对齐 多样化的数据传输路径 广泛的数据源与目标 最大数据长度 DMA寄存器详解 增量与循环模式 DMA中断机制 ​编辑 小实验&#xff1a;DMA-ADC串口发送 引言 在现代嵌入…

推荐一款Win11主题WPF UI框架

最近在微软商店&#xff0c;官方上架了新款Win11风格的WPF版UI框架【WPF Gallery Preview 1.0.0.0】,这款应用引入了前沿的Fluent Design UI设计&#xff0c;为用户带来全新的视觉体验。 WPF Gallery简介 做为一关注前沿资讯的开发人员&#xff0c;首先关注的是应用WPF Gallery…

马斯克公布xAI Grok-2大语言模型将于8月推出;GPT-5仍需时日

&#x1f989; AI新闻 &#x1f680; 马斯克公布xAI Grok-2大语言模型将于8月推出 摘要&#xff1a;7月1日&#xff0c;马斯克在X平台宣布&#xff0c;其人工智能初创公司xAI的新大语言模型Grok-2将于8月推出。此前&#xff0c;xAI已发布了Grok-1.5和Grok-1.5 Vision模型。马…

2024年【安全员-C证】考试及安全员-C证免费试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 安全员-C证考试根据新安全员-C证考试大纲要求&#xff0c;安全生产模拟考试一点通将安全员-C证模拟考试试题进行汇编&#xff0c;组成一套安全员-C证全真模拟考试试题&#xff0c;学员可通过安全员-C证免费试题全真模…

飞睿智能无线高速uwb安全数据传输模块,低功耗、抗干扰超宽带uwb芯片传输速度技术新突破

在信息化的时代&#xff0c;数据传输的速度和安全性无疑是每个企业和个人都极为关注的话题。随着科技的飞速发展&#xff0c;超宽带&#xff08;Ultra-Wideband&#xff0c;简称UWB&#xff09;技术凭借其性能和广泛的应用前景&#xff0c;逐渐成为了数据传输领域的新星。今天&…

C语言学习笔记[21]:分支语句if...else

C语言是结构化的程序设计语言 顺序结构选择结构循环结构 分支语句对应的就是选择结构&#xff0c;循环语句对应的就是循环结构 分支语句 if...elseswitch 循环语句 whilefordo...while goto语句 语句 C语言中由分号隔开的就是一条语句&#xff0c;比如&#xff1a; #…

这个暑假,带娃就交给华为儿童手表5 Pro吧

一年一度孩子们最期待的暑期终于到啦&#xff01;在这个充足的时间段里&#xff0c;孩子们可以尽情的释放他们的热情与好奇心&#xff0c;家长们也可以努力为孩子们创造更多的回忆。但是&#xff0c;不少家长暑期带娃总是发愁&#xff0c;宝贝们玩的多&#xff0c;家长们需要注…