【C#进阶】C# 反射
| 序号 | 系列文章 |
|---|---|
| 11 | 【C#基础】C# 预处理器指令 |
| 12 | 【C#基础】C# 文件与IO |
| 13 | 【C#进阶】C# 特性 |
文章目录
- 前言
- 1,反射的概念
- 2,使用反射访问特性
- 3,反射的用途
- 4,反射的优缺点比较
- 4.1 优点:
- 4.2 缺点:
- 5,System.Reflection 命名空间
- 5.1 获取程序集中的信息
- 5.2 获取程序集中的类型
- 5.3 获取程序集中的成员
- 5.4 创建类型的实例对象
- 结语
前言
✋ 大家好,我是writer桑,本章为大家介绍 C# 中的反射。
1,反射的概念
反射指的是程序可以访问,检测和修改它本身状态或行为的一种行为。 其中访问的目标包括程序集1、模块和类型对象等。可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型,然后调用其方法或访问器字段和属性。反射行为也常常用来访问应用在程序上的特性。
代码示例:(简单展示)
using System;
using System.Reflection;public class Example
{static void Main(){// 使用反射获取程序集的信息:Assembly info = typeof(int).Assembly;Console.WriteLine(info);}
}
运行结果:

在上例中,使用 typeof 方法获取已加载的 int 程序集的完整名称。
2,使用反射访问特性
在前面的一章中,我们讨论到了 C# 使用反射访问特性的操作。在本章中就可以使用反射的操作来访问 Example 类中的元数据。
代码示例:
using System;[System.AttributeUsage(System.AttributeTargets.Class |System.AttributeTargets.Struct)
]
public class AuthorAttribute : System.Attribute
{public string name; public double age;// 构造函数public AuthorAttribute(string name){this.name = name;age = 11;}
}[Author("writer桑", age = 21)]
public class Example
{// Example类成员
}public class Program
{static void Main(){// 访问 Example 类应用的特性 Type type = typeof(Example);// 遍历输出 foreach(Object attributes in type.GetCustomAttributes(true)){AuthorAttribute author = (AuthorAttribute)attributes;Console.WriteLine(author.age);Console.WriteLine(author.name); }}
}
运行结果:

3,反射的用途
反射的用途可以总结为以下几点:
- 需要访问程序中的元数据的特性时。(点击了解更多)
- 检查和实例化程序集中的类型时。
- 在运行时构建新的类型,比如使用 System.Reflection.Emit 中的类。(点击了解更多)
- 执行后期绑定,访问在运行时创建的类型上的方法时。(点击了解更多)
4,反射的优缺点比较
反射的优缺点比较:
4.1 优点:
- 反射是运行期的操作,提高了程序的灵活性和扩展性。
- 降低耦合度2,提高自适应能力。
- 允许动态的创建和使用对象,无需提前硬编码3目标对象。
4.2 缺点:
- 性能较低,反射是运行期4的代码,在性能方面不如直接的编译型5代码。
- 可读性较低,使用反射会使得程序本身的逻辑变得复杂,在可读性方面不如直接的代码来的简洁。
- 维护成本变高,反射是一种绕过了源代码的技术, 因而在维护的方面难度较高。
5,System.Reflection 命名空间
System.Reflection 命名空间中包含通过检测托管代码中程序集、模块、成员、参数和其他实体的元数据来检索其相关信息的类型。同时也可以用于操作加载类型的实例,例如钩子函数6或调用方法。在 C# 中,实现反射操作常常需要用到 System.Reflection 命名空间中的类和方法。
列举一些 System.Reflection 命名空间中常用的反射操作:
5.1 获取程序集中的信息
System.Reflection 命名空间中的 Assembly.FullName 等属性可以用来获取程序集中的信息。
代码示例:
using System;
using System.Reflection;public class Example
{private int factor;public Example(int f){factor = f;}public int SampleMethod(int x){Console.WriteLine($"实例方法的执行:({x})");return x * factor;}public static void Main(){Assembly assem = typeof(Example).Assembly;Console.WriteLine($"程序集的全程:{assem.FullName}");// 可以使用 AssemblyName 类型解析完整名称。AssemblyName assemName = assem.GetName();Console.WriteLine($"名称: {assemName.Name}");//从程序集创建一个对象,并传入正确的数字//构造函数的参数类型。Object o = assem.CreateInstance("Example", false, BindingFlags.ExactBinding, null, new Object[] { 2 }, null, null);// 对对象的实例方法进行晚绑定调用。MethodInfo m = assem.GetType("Example").GetMethod("SampleMethod");Object ret = m.Invoke(o, new Object[] { 42 });Console.WriteLine($"示例方法的返回值为:{ret}");Console.WriteLine($"程序集入口点:{assem.EntryPoint}");}
}
运行结果:

5.2 获取程序集中的类型
System.Reflection 命名空间中的 Assembly.GetExportedTypes 方法可以用来获取程序集中定义的公共类型,这些公共类型在程序集外可见。
代码示例:
using System;
using System.Reflection;public class PublicClass
{public class PublicNestedClass { }protected class ProtectedNestedClass { }internal class FriendNestedClass { }private class PrivateNestedClass { }
}public class Example
{public static void Main(){// 获取程序集中定义的公共类型 foreach (Type t in typeof(Example).Assembly.GetExportedTypes()){Console.WriteLine(t);}}
}
运行结果:

5.3 获取程序集中的成员
System.Reflection 命名空间中的 MemberInfo 类中的属性和方法可以用来获取有关成员属性的信息并提供对成员元数据的访问权限。
代码示例:
using System;
using System.Reflection;public class Example
{// 显示应用到指定成员的自定义属性 public static void DisplayAttributes(Int32 indent, MemberInfo mi){// 获取自定义属性集;如果不存在,则返回。object[] attrs = mi.GetCustomAttributes(false);if (attrs.Length == 0) { return; }// 显示应用于该成员的自定义属性。Display(indent + 1, "属性:");foreach (object o in attrs){Display(indent + 2, "{0}", o.ToString());}}// 显示一个缩进的格式化字符串。 public static void Display(Int32 indent, string format, params object[] param){Console.Write(new string(' ', indent * 2));Console.WriteLine(format, param);}public static void Main(){//该变量保存缩进的数量, 显示每一行信息时使用。Int32 indent = 0;// 显示加载到这个 AppDomain 第一个 程序集的信息。Assembly b = AppDomain.CurrentDomain.GetAssemblies()[0];Display(indent, "程序集: {0}", b);// 显示从此程序集导出的 第一个 类型的相关信息。 indent += 1;Type t = b.GetExportedTypes()[0];Display(0, "");Display(indent, "类型: {0}", t);// 遍历显示成员及其自定义属性。indent += 1;foreach (MemberInfo mi in t.GetMembers()) // GetMembers 方法{Display(indent, "成员: {0}", mi.Name);DisplayAttributes(indent, mi);// 如果成员是一个方法,显示它的参数信息。if (mi.MemberType == MemberTypes.Method){foreach (ParameterInfo pi in ((MethodInfo)mi).GetParameters()){Display(indent + 1, "参数: 类型={0}, 名字={1}", pi.ParameterType, pi.Name);}}// 如果成员是一个属性,显示关于属性的访问方法的信息。 if (mi.MemberType == MemberTypes.Property){foreach (MethodInfo am in ((PropertyInfo)mi).GetAccessors()){Display(indent + 1, "访问器方法: {0}", am);}}}}
}
运行结果:

5.4 创建类型的实例对象
System.Reflection 空间中的 Assembly.CreateInstance 方法可以用来获取包含当前执行的代码的程序集,以此来创建类型的实例对象。
代码示例:
using System;
using System.Reflection;public class Person
{private string _name;public Person(){ }public Person(string name){this._name = name;}public string Name{get { return this._name; }set { this._name = value; }}public override string ToString(){return this._name;}
}public class Example
{public static void Main(){Assembly assem = typeof(Person).Assembly;// 创建 Person 类的实例化对象 Person p = (Person)assem.CreateInstance("Person");if (!(p == null)){p.Name = "John";Console.WriteLine($"实例化值为'{p}'的{p.GetType().Name}对象");}else{Console.WriteLine("无法实例化Person对象。");}}
}
运行结果:

点击了解更多 System.Reflection 命名空间的使用。
结语
👋 以上就是关于 C# 反射的介绍啦,希望对大家有所帮助。感谢大家的支持。
程序集(assembly):是一个及一个以上托管模块,以及一些资源文件的逻辑组合。在 .NET 中,dll与exe文件都是程序集。 ↩︎
耦合性(或称耦合力或耦合度):是一种软件度量,是指一程序中,模块及模块之间信息或参数依赖的程度。 ↩︎
硬编码:是将数据直接嵌入到程序或其他可执行对象的源代码中的软件开发实践,与从外部获取数据或在运行时生成数据不同。 ↩︎
运行期:是把编译后的文件交给计算机执行,直到程序运行结束。 ↩︎
编译期:是指把源码交给编译器编译成计算机可以执行的文件的过程。 ↩︎
钩子函数:是 Windows 消息处理机制的一部分,是指在程序正常运行中接受信息之前预先启动的函数,用来检查和修改传给该程序的信息,(钩子)实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。 ↩︎
相关文章:
【C#进阶】C# 反射
序号系列文章11【C#基础】C# 预处理器指令12【C#基础】C# 文件与IO13【C#进阶】C# 特性文章目录前言1,反射的概念2,使用反射访问特性3,反射的用途4,反射的优缺点比较4.1 优点:4.2 缺点:5,System…...
公网NAT网关与VPC NAT网关介绍与实践
NAT网关介绍 NAT网关是一种网络地址转换服务,提供NAT代理(SNAT和DNAT)能力。 公有云NAT分为公网NAT网关和VPC NAT网关。 1)公网NAT网关:提供公网地址转换服务。 2)VPC NAT网关:提供私网地址转换…...
Windows中UWP、WPF和Windows窗体的区别
Windows 中开发应用(或者可以说客户端)有三种方法: UWP(Universal Windows Platform)、WPF(Windows Presentation Foundation)和 Windows 窗体(Win Forms)。这三种方法在…...
Flink从入门到精通系列(一)
1、Flink概述 Apache Flink 是一个框架和分布式处理引擎,用于在, 无边界和有边界数据流上进行有状态的计算 ,Flink 能在所有常见集群环境中运行,并能以内存速度和任意规模进行计算。 Apache Flink 功能强大,支持开发…...
云原生应用风险介绍
本博客地址:https://security.blog.csdn.net/article/details/129303616 一、传统风险 传统风险主要是注入、敏感数据泄露、跨站脚本、配置错误等等,这些传统的安全风险在云原生应用中也是存在的,这里就不具体展开说了。 二、云原生应用架…...
什么是测试用例设计?
前言 想要进行测试自动化的团队都会遇到这个问题:自动化的成功和编码能力有多大的关联?现在更多的招聘信息越来越偏重于对测试人员的编程能力的要求,似乎这个问题的答案是极大的正关联性。 测试人员可以将编码能力用于与测试相关的各种目的…...
数据分析:基于K-近邻(KNN)对Pima人糖尿病预测分析
数据分析:基于K-近邻(KNN)对Pima人糖尿病预测分析 作者:AOAIYI 作者简介:Python领域新星作者、多项比赛获奖者:AOAIYI首页 😊😊😊如果觉得文章不错或能帮助到你学习,可以点赞&#x…...
Kettle体系结构及源码解析
介绍 ETL是数据抽取(Extract)、转换(Transform)、装载(Load)的过程。Kettle是一款国外开源的ETL工具,有两种脚本文件transformation和job,transformation完成针对数据的基础转换&…...
大数据 | (二)SSH连接报错Permission denied
大数据 | (三)centos7图形界面无法执行yum命令:centos7图形界面无法执行yum命令 哈喽!各位CSDN的朋友们大家好! 今天在执行Hadoop伪分布式安装时,遇到了一个问题,在此跟大家分享, …...
前端——6.文本格式化标签和<div>和<span>标签
这篇文章,我们来讲一下HTML中的文本格式化标签 目录 1.文本格式化标签 1.1介绍 1.2代码演示 1.3小拓展 2.div和span标签 2.1介绍 2.2代码演示 2.3解释 3.小结 1.文本格式化标签 在网页中,有时需要为文字设置粗体、斜体和下划线等效果…...
浅谈Xpath注入漏洞
目录 知识简介 攻击简介 基础语法 语法演示 漏洞简介 漏洞原理 漏洞复现 Xpath盲注 知识简介 攻击简介 XPath注入攻击是指利用XPath 解析器的松散输入和容错特性,能够在 URL、表单或其它信息上附带恶意的XPath 查询代码,以获得权限信息的访问权…...
Oracle LogMiner分析归档日志
目录:Oracle LogMiner分析归档日志一、准备测试环境1、开启数据库归档日志2、打开数据库最小附加日志3、设置当前session时间日期格式二、创建测试数据1、创建数据2、数据落盘三、日志发掘测试挖掘在上次归档的Redo Log File1.确定最近归档的Redo Log File2.指定要分…...
趣味三角——第15章——傅里叶定理
第15章 傅里叶定理(Fourier’s Theorem) Fourier, not being noble, could not enter the artillery, although he was a second Newton. (傅立叶出生并不高贵,因此按当时的惯例进不了炮兵部队,虽然他是第二个牛顿。) —Franois Jean Dominique Arag…...
市场营销的核心是什么?
之所以写下「市场营销的核心是什么?」这篇文章,是因为这几天刚读完了《经理人参阅:市场营销》这本书。作为一个有着近十年工作经验的市场营销从业人员,看完这本书也产生了很多新的想法,也想记录一下,遂成此…...
c/cpp - 多线程/进程 多进程
c/cpp - 多线程/进程 多进程多进程创建多进程进程等待多进程 宏观上 两个进程完全并发的 父子进程具有互相独立的进程空间 父进程结束,不影响子进程的执行 创建多进程 #include <sys/types.h> #include <unistd.h> #include <stdio.h>int main()…...
MySQL必知必会 | 存储过程、游标、触发器
使用存储过程 存储过程 简单来说就是为了以后的使用而保存的一条或多条MySQL语句的集合。 我觉得就是封装了一组sql语句 为什么需要存储过程(简单来说就是,简单、安全、高性能 通过把处理封装在容易使用的单元中,简化复杂操作所有开发人员…...
优化Facebook广告ROI的数据驱动方法:从投放到运营
“投放广告并不是最终的目的,关键在于如何最大程度地利用数据驱动的方法来提高广告投放的回报率(ROI)”Facebook广告是现代数字营销中最为常见和重要的广告形式之一。但是,要让Facebook广告真正发挥作用,需要通过数据驱…...
动态规划入门经典问题讲解
最近开始接触动态规划问题,以下浅谈(或回顾)一下这些问题的求解过程。解题思路对于动态规划问题,由于最终问题的求解需要以同类子问题作为基础,故需要定义一个dp数组(一维或二维)来记录问题求解…...
快速入门深度学习1(用时1h)
速通《动手学深度学习》1写在最前面0.内容与结构1.深度学习简介1.1 问题引入1.2 思路:逆向思考1.3 跳过1.4 特点1.5 小结2.预备知识(MXNet版本,学错了。。。。)2.1 获取和运行本书的代码2.2 数据操作2.2.1 略过2.2.2 小结2.3 自动…...
PaddleOCR关键信息抽取(KIE)的训练(SER训练和RE训练)错误汇总
1.SER训练报错: SystemError: (Fatal) Blocking queue is killed because the data reader raises an exception 1.1.问题描述 在执行训练任务的时候报错 单卡训练 python3 tools/train.py -c train_data/my_data/ser_vi_layoutxlm_xfund_zh.yml错误信息如下: T…...
GitHub开源项目协作利器:Cosmos-Reason1-7B智能分析Issue与PR
GitHub开源项目协作利器:Cosmos-Reason1-7B智能分析Issue与PR 如果你维护过一个活跃的开源项目,肯定对这种感觉不陌生:每天打开GitHub,通知列表又多了几十条未读。新的Issue五花八门,有功能请求、有Bug报告、还有使用…...
告别EEPROM!用STM32的BKP备份寄存器实现低成本数据存储(F103C8T6实战)
低成本数据存储方案:STM32 BKP备份寄存器实战指南 引言 在嵌入式系统开发中,数据存储一直是个绕不开的话题。传统方案往往依赖外置EEPROM或Flash芯片,但这意味着额外的物料成本和PCB空间占用。对于学生创客、硬件初创团队或者资源受限的小型项…...
Fish Speech-1.5镜像部署稳定性测试:7×24小时高负载压力测试报告
Fish Speech-1.5镜像部署稳定性测试:724小时高负载压力测试报告 1. 测试背景与目标 Fish Speech V1.5作为当前领先的文本转语音模型,基于超过100万小时的多语言音频数据训练而成,支持包括中文、英语、日语在内的13种语言。在实际应用中&…...
抖音无水印下载终极指南:3分钟学会批量保存高清视频
抖音无水印下载终极指南:3分钟学会批量保存高清视频 【免费下载链接】douyin-downloader 项目地址: https://gitcode.com/GitHub_Trending/do/douyin-downloader 还在为抖音视频的水印烦恼吗?想要保存喜欢的舞蹈教学、美食教程或搞笑片段&#x…...
QNX系统线程优先级实战:如何避免嵌入式开发中的调度陷阱?
QNX线程优先级实战:嵌入式开发中的调度优化与陷阱规避 在嵌入式系统开发领域,QNX以其微内核架构和实时性能著称,而线程优先级调度机制正是其核心优势之一。然而,这也是一把双刃剑——不当的优先级设置可能导致系统性能下降、响应延…...
FRCRN Git仓库管理:代码版本控制与协作开发指南
FRCRN Git仓库管理:代码版本控制与协作开发指南 如果你对语音降噪技术感兴趣,特别是FRCRN这个效果不错的模型,并且想为它的开源项目贡献一份力量,那么这篇文章就是为你准备的。很多开发者有很好的想法,但一想到要参与…...
卷积神经网络(CNN)原理问答助手:通义千问1.5-1.8B模型在AI教育中的应用
卷积神经网络(CNN)原理问答助手:通义千问1.5-1.8B模型在AI教育中的应用 1. 引言 你有没有过这样的经历?翻开一本机器学习的教材,看到“卷积神经网络”这几个字,再配上几页复杂的数学公式和网络结构图&…...
ClearerVoice-Studio目标说话人提取案例:AV_MossFormer2_TSE_16K人脸驱动音频提取
ClearerVoice-Studio目标说话人提取案例:AV_MossFormer2_TSE_16K人脸驱动音频提取 1. 引言:从视频中精准提取目标人声 在日常工作和生活中,我们经常遇到这样的场景:一段会议录像中有多人发言,但我们只需要提取其中某…...
在Java中如何处理长数字读写
Java处理长数字需要下划线分隔符来提高可读性(编译期忽略)、BigDecimal(字符串结构)优先选择long防溢出,精确计算、根据String统一分析长数字输入。Java处理长数字的关键是正确使用数字面量分隔符,选择合适的数据类型,并注意浮点数的精度。直…...
【华为OD机考真题】智慧交通·路口最短时间问题 (Java/Go)
一、题目 假定街道是棋盘型的,每格距离相等,车辆通过每格街道需要时间均为 timePerRoad;街道的街口(交叉点)有交通灯,灯的周期 T(lights[row][col])各不相同;车辆可直行、左转和右转,其中直行和左转需要等相应T时间的交通灯才可通…...
