当前位置: 首页 > news >正文

【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,反射的用途

反射的用途可以总结为以下几点:

  1. 需要访问程序中的元数据的特性时。(点击了解更多)
  2. 检查和实例化程序集中的类型时。
  3. 在运行时构建新的类型,比如使用 System.Reflection.Emit 中的类。(点击了解更多)
  4. 执行后期绑定,访问在运行时创建的类型上的方法时。(点击了解更多)

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# 反射的介绍啦,希望对大家有所帮助。感谢大家的支持。


  1. 程序集(assembly):是一个及一个以上托管模块,以及一些资源文件的逻辑组合。在 .NET 中,dll与exe文件都是程序集。 ↩︎

  2. 耦合性(或称耦合力或耦合度):是一种软件度量,是指一程序中,模块及模块之间信息或参数依赖的程度。 ↩︎

  3. 硬编码:是将数据直接嵌入到程序或其他可执行对象的源代码中的软件开发实践,与从外部获取数据或在运行时生成数据不同。 ↩︎

  4. 运行期:是把编译后的文件交给计算机执行,直到程序运行结束。 ↩︎

  5. 编译期:是指把源码交给编译器编译成计算机可以执行的文件的过程。 ↩︎

  6. 钩子函数:是 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.文本格式化标签 在网页中,有时需要为文字设置粗体、斜体和下划线等效果&#xf…...

浅谈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 - 多线程/进程 多进程多进程创建多进程进程等待多进程 宏观上 两个进程完全并发的 父子进程具有互相独立的进程空间 父进程结束&#xff0c;不影响子进程的执行 创建多进程 #include <sys/types.h> #include <unistd.h> #include <stdio.h>int main()…...

MySQL必知必会 | 存储过程、游标、触发器

使用存储过程 存储过程 简单来说就是为了以后的使用而保存的一条或多条MySQL语句的集合。 我觉得就是封装了一组sql语句 为什么需要存储过程&#xff08;简单来说就是&#xff0c;简单、安全、高性能 通过把处理封装在容易使用的单元中&#xff0c;简化复杂操作所有开发人员…...

优化Facebook广告ROI的数据驱动方法:从投放到运营

“投放广告并不是最终的目的&#xff0c;关键在于如何最大程度地利用数据驱动的方法来提高广告投放的回报率&#xff08;ROI&#xff09;”Facebook广告是现代数字营销中最为常见和重要的广告形式之一。但是&#xff0c;要让Facebook广告真正发挥作用&#xff0c;需要通过数据驱…...

动态规划入门经典问题讲解

最近开始接触动态规划问题&#xff0c;以下浅谈&#xff08;或回顾&#xff09;一下这些问题的求解过程。解题思路对于动态规划问题&#xff0c;由于最终问题的求解需要以同类子问题作为基础&#xff0c;故需要定义一个dp数组&#xff08;一维或二维&#xff09;来记录问题求解…...

快速入门深度学习1(用时1h)

速通《动手学深度学习》1写在最前面0.内容与结构1.深度学习简介1.1 问题引入1.2 思路&#xff1a;逆向思考1.3 跳过1.4 特点1.5 小结2.预备知识&#xff08;MXNet版本&#xff0c;学错了。。。。&#xff09;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错误信息如下&#xff1a; T…...

变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析

一、变量声明设计&#xff1a;let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性&#xff0c;这种设计体现了语言的核心哲学。以下是深度解析&#xff1a; 1.1 设计理念剖析 安全优先原则&#xff1a;默认不可变强制开发者明确声明意图 let x 5; …...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八

现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet&#xff0c;点击确认后如下提示 最终上报fail 解决方法 内核升级导致&#xff0c;需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案

问题描述&#xff1a;iview使用table 中type: "index",分页之后 &#xff0c;索引还是从1开始&#xff0c;试过绑定后台返回数据的id, 这种方法可行&#xff0c;就是后台返回数据的每个页面id都不完全是按照从1开始的升序&#xff0c;因此百度了下&#xff0c;找到了…...

前端导出带有合并单元格的列表

// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...

汽车生产虚拟实训中的技能提升与生产优化​

在制造业蓬勃发展的大背景下&#xff0c;虚拟教学实训宛如一颗璀璨的新星&#xff0c;正发挥着不可或缺且日益凸显的关键作用&#xff0c;源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例&#xff0c;汽车生产线上各类…...

P3 QT项目----记事本(3.8)

3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...

Typeerror: cannot read properties of undefined (reading ‘XXX‘)

最近需要在离线机器上运行软件&#xff0c;所以得把软件用docker打包起来&#xff0c;大部分功能都没问题&#xff0c;出了一个奇怪的事情。同样的代码&#xff0c;在本机上用vscode可以运行起来&#xff0c;但是打包之后在docker里出现了问题。使用的是dialog组件&#xff0c;…...

重启Eureka集群中的节点,对已经注册的服务有什么影响

先看答案&#xff0c;如果正确地操作&#xff0c;重启Eureka集群中的节点&#xff0c;对已经注册的服务影响非常小&#xff0c;甚至可以做到无感知。 但如果操作不当&#xff0c;可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...