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

C# 反射详解

反射是C#中的一个强大特性,允许程序在运行时检查和操作类型和对象的信息。

通过反射,你可以获取类型的属性方法构造函数等信息,并可以动态创建对象、调用方法或访问属性,甚至可以实现某些框架或库的核心功能。

反射的基本概念

  1. 类型信息:反射使我们能够获取类型的名称、成员(如属性、方法、字段)、基类、接口等信息。
  2. 动态创建对象:可以在运行时创建一个类的实例,而不需要在编译时知道具体的类。
  3. 访问成员:通过反射,可以访问类的私有成员,甚至是静态成员。

反射的常用类

反射的主要类都在 System.Reflection 命名空间中,以下是一些重要的类:

  • Type:表示类型的信息,可以用来获取类的信息,包括方法、属性、字段等。
  • Assembly:表示一个程序集,提供有关程序集的元数据。
  • MethodInfo:表示方法的信息,可以用来调用方法。
  • PropertyInfo:表示属性的信息,可以用来获取或设置属性的值。

反射常用类及其常用方法表

类名常用方法描述
TypeGetProperties()获取公共属性的数组。
GetMethods()获取公共方法的数组。
GetFields()获取公共字段的数组。
GetConstructors()获取构造函数的信息。
GetInterfaces()获取该类型实现在的所有接口。
GetCustomAttributes()获取应用于当前类型的所有自定义特性(Attributes)。
BaseType获取此类型的基类型(父类)。
PropertyInfoGetValue(object obj)获取指定对象上属性的值。
SetValue(object obj, object value)设置指定对象上属性的值。
CanRead指示属性是否有获取访问器。
CanWrite指示属性是否有设置访问器。
MethodInfoInvoke(object obj, object[] parameters)调用方法。
GetParameters()获取方法的参数信息。
ReturnType获取方法的返回类型。
IsStatic指示方法是否为静态方法。
FieldInfoGetValue(object obj)获取指定对象上字段的值。
SetValue(object obj, object value)设置指定对象上字段的值。
FieldType获取字段的类型。
ConstructorInfoInvoke(object[] parameters)调用构造函数以创建实例。
GetParameters()获取构造函数的参数信息。
IsStatic指示构造函数是否为静态构造函数。
AssemblyGetTypes()获取程序集中的所有类型。
GetName()获取程序集的名称信息。
GetCustomAttributes()获取应用于该程序集的所有自定义特性。

typeof 与 GetType

1. typeof 操作符

定义

  • typeof 是一个操作符,用于在编译时获取某个类型的 Type 对象。它适用于任何类型,包括类、结构、接口和基本类型。

用法

  • typeof 的语法是:Type type = typeof(SomeType);
  • 它返回的结果是 System.Type 的一个实例,表示指定类型的信息,能够用于反射。

2. GetType 方法

定义

  • GetType 是一个实例方法,它属于所有 .NET 对象的基类 Object。当你在一个对象实例上调用 GetType 方法时,它会返回该实例的 Type 对象。

用法

  • GetType 的语法是:Type type = someObject.GetType();
  • 它用于获取对象的实际类型信息。

特点typeofGetType
类型获取方式在编译时获取类型信息在运行时获取对象实例的类型信息
使用场景获取静态类型的 Type 对象获取对象实例的 Type 对象
返回类型总是返回特定类型的 Type返回调用该方法的对象的实际类型的 Type
语法Type type = typeof(ClassName);Type type = instance.GetType();

反射的使用示例

1. 获取类型信息

使用 Type 类可以获取对象的类型信息:

我们定义一个简单的类 Person,然后使用反射获取它的类型信息。

在此,我们将typeof和GetType进行对比。

using System;
namespace Tdm;
public class Person
{public string Name { get; set; }public int Age { get; set; }public void DisplayInfo(){Console.WriteLine($"姓名: {Name}, 年龄: {Age}");}
}class Program
{static void Main(){Person person = new Person(); // 创建 Person 对象// 使用 GetType 方法Type typeFromInstance = person.GetType();Console.WriteLine("使用 GetType() 输出:");Console.WriteLine("类型名称: " + typeFromInstance.Name);       // 输出:类型名称: PersonConsole.WriteLine("命名空间: " + typeFromInstance.Namespace); // 输出:命名空间: (Tdm)// 使用 typeof 操作符Type typeFromTypeOf = typeof(Person); Console.WriteLine("\n使用 typeof 输出:");Console.WriteLine("类型名称: " + typeFromTypeOf.Name);       // 输出:类型名称: PersonConsole.WriteLine("命名空间: " + typeFromTypeOf.Namespace); // 输出:命名空间: (Tdm)}
}
使用 GetType() 输出:
类型名称: Person
命名空间: (Tdm)使用 typeof 输出:
类型名称: Person
命名空间: (Tdm)

2. 动态创建对象

我们使用反射动态创建 Person 对象,并设置其属性。

using System;public class Person
{public string Name { get; set; }public int Age { get; set; }public void DisplayInfo(){Console.WriteLine($"姓名: {Name}, 年龄: {Age}");}
}class Program
{static void Main(){Type personType = typeof(Person); // 获取 Person 类型Person person = (Person)Activator.CreateInstance(personType); // 动态创建 Person 实例// 设置属性值person.Name = "小明"; // 设置姓名person.Age = 25;      // 设置年龄person.DisplayInfo(); // 调用方法显示信息,输出:姓名: 小明, 年龄: 25}
}

3. 访问和修改属性

我们将使用反射访问和修改 Person 类的属性。

using System;
using System.Reflection;public class Person
{public string Name { get; set; } // 姓名属性public int Age { get; set; }      // 年龄属性
}class Program
{static void Main(){Person person = new Person(); // 创建 Person 对象Type type = person.GetType(); // 获取类型信息// 获取属性信息PropertyInfo nameProperty = type.GetProperty("Name"); // 获取 Name 属性PropertyInfo ageProperty = type.GetProperty("Age");   // 获取 Age 属性// 设置属性值nameProperty.SetValue(person, "张三"); // 通过反射设置 Name 属性ageProperty.SetValue(person, 30);      // 通过反射设置 Age 属性// 获取属性值并输出Console.WriteLine($"{nameProperty.Name}: {nameProperty.GetValue(person)}"); // 输出:Name: 张三Console.WriteLine($"{ageProperty.Name}: {ageProperty.GetValue(person)}");     // 输出:Age: 30}
}

4.调用方法

我们将使用反射调用 Person 类的方法。

using System;
using System.Reflection;public class Person
{public void DisplayInfo(string greeting) // 显示信息的方法{Console.WriteLine($"{greeting}, 我是C#开发工程师!。"); // 输出问候信息}
}class Program
{static void Main(){Person person = new Person(); // 创建 Person 对象Type type = person.GetType(); // 获取类型信息// 获取方法信息MethodInfo methodInfo = type.GetMethod("DisplayInfo"); // 获取 DisplayInfo 方法// 调用方法并传递参数methodInfo.Invoke(person, new object[] { "你好" }); // 输出:你好,我是C#开发工程师!}
}

反射的使用场景

1. 序列化和反序列化

反射非常适合于在对象和数据格式(如 JSON 或 XML)之间进行转换。使用反射,可以动态遍历对象的属性,将其值提取出来,构建相应的序列化格式。

示例:将一个对象转换为 JSON 字符串,或将一个 JSON 字符串转换为对象。

2. 依赖注入

许多现代框架(如 ASP.NET Core)使用反射来实现依赖注入。在运行时,框架可以通过反射创建对象实例和解析依赖关系。

示例:在 ASP.NET Core 中,使用反射自动识别控制器并注入其依赖服务。

3. 动态类型处理

在处理动态类型(例如,使用动态对象或 COM 组件)时,反射可以帮助获取类型信息并处理其方法和属性。

示例:通过反射操作一个未知类型的对象,尤其是在不确定其类型时。

注意事项

1. 性能问题

反射涉及到查找和动态调用,通常比直接调用方法慢。在性能敏感的代码中,应尽量减少反射的使用,或者对反射结果进行缓存。

2. 类型安全

反射不进行编译时类型检查,因此可能导致运行时错误。如果获取的成员不存在,程序将抛出异常。在使用反射时,务必保证类型的匹配。

        

相关文章:

C# 反射详解

反射是C#中的一个强大特性,允许程序在运行时检查和操作类型和对象的信息。 通过反射,你可以获取类型的属性、方法、构造函数等信息,并可以动态创建对象、调用方法或访问属性,甚至可以实现某些框架或库的核心功能。 反射的基本概念…...

pgadmin安装后运行不能启动界面的问题

在本人机器上安装了pgsql10后,自带的pgadmin安装后运行时能打开edge并显示数据库server和数据库的,后来又安装了pgsql17,结果安装后想打开pgadmin,结果一直在等待最后,爆出类似于下面的错误。 pgAdmin Runtime Enviro…...

跳表(Skip List)

跳表(Skip List) 跳表是一种用于快速查找、插入和删除的概率型数据结构,通常用于替代平衡二叉搜索树(如 AVL 树或红黑树)。跳表通过在有序链表的基础上增加多层索引,使得查找操作的平均时间复杂度降低&…...

前端实现把整个页面转成PDF保存到本地(DOM转PDF)

一、问题 遇到一个需求,就是要把整个看板页面导出成PDF用在汇报,也就是要把整个DOM生成一个PDF保存到本地。 二、解决方法 1、解决思路:使用插件 jspdf 和 html2canvas,我用的版本如下图 2、代码实现 import { jsPDF } from …...

Vue 3 学习文档(一)

最近打算做一个项目,涉及到一些前端的知识,因上一次接触前端已经是三四年前了,所以捡一些简单的功能做一下复习。 响应式函数:reactive 和 ref属性绑定:v-bind 和简写语法事件监听:v-on 和简写语法 双向绑…...

【适配】屏幕拖拽-滑动手感在不同分辨率下的机型适配

接到一个需求是类似下图的3D多房间视角,需要拖拽屏幕 问题 在做这种屏幕拖拽的时候发现,需要拖拽起来有跟手的感觉,会存在不同分辨率机型的适配问题。 即:美术调整好了机型1的手感,能做到手指按下顶层地板上下挪动&…...

牛客周赛 Round 69(A~E)

文章目录 A 构造C的歪思路code B 不要三句号的歪思路code C 仰望水面的歪思路code D 小心火烛的歪思路code E 喜欢切数组的红思路code 牛客周赛 Round 69 A 构造C的歪 思路 签到题,求出公差d,让最大的数加上公差d即可 code int a,b;cin >> a &…...

Spring Boot 实战:分别基于 MyBatis 与 JdbcTemplate 的数据库操作方法实现与差异分析

1. 数据库新建表 CREATE TABLE table_emp(id INT AUTO_INCREMENT,emp_name CHAR(100),age INT,emp_salary DOUBLE(10,5),PRIMARY KEY(id) );INSERT INTO table_emp(emp_name,age,emp_salary) VALUES("tom",18,200.33); INSERT INTO table_emp(emp_name,age,emp_sala…...

【jmeter】服务器使用jmeter压力测试(从安装到简单压测示例)

一、服务器上安装jmeter 1、官方下载地址,https://jmeter.apache.org/download_jmeter.cgi 2、服务器上用wget下载 # 更新系统 sudo yum update -y# 安装 wget 以便下载 JMeter sudo yum install wget -y# 下载 JMeter 压缩包(使用 JMeter 官方网站的最…...

使用Python实现自动化邮件通知:当长时程序运行结束时

使用Python实现自动化邮件通知:当长时程序运行结束时 前提声明 本代码仅供学习和研究使用,不得用于商业用途。请确保在合法合规的前提下使用本代码。 目录 引言项目背景项目设置代码分析 导入所需模块定义邮件发送函数发送邮件 实现步骤结语全部代码…...

框架学习07 - SpringMVC 其他功能实现

一. 拦截器实现HandlerInterceptor 接⼝ SpringMVC 中的 Interceptor 拦截器也是相当重要和相当有⽤的,它的主要作⽤是拦截⽤户的请求并进⾏相应的处理。⽐如通过它来进⾏权限验证,或者是来判断⽤户是否登陆等操作。对于 SpringMVC 拦截器的定义⽅式有两…...

NAT:连接私有与公共网络的关键技术(4/10)

一、NAT 的工作原理 NAT 技术的核心功能是将私有 IP 地址转换为公有 IP 地址,使得内部网络中的设备能够与外部互联网通信。其工作原理主要包括私有 IP 地址到公有 IP 地址的转换、端口号映射以及会话表维护这几个步骤。 私有 IP 地址到公有 IP 地址的转换&#xff1…...

RabbitMQ2:介绍、安装、快速入门、数据隔离

欢迎来到“雪碧聊技术”CSDN博客! 在这里,您将踏入一个专注于Java开发技术的知识殿堂。无论您是Java编程的初学者,还是具有一定经验的开发者,相信我的博客都能为您提供宝贵的学习资源和实用技巧。作为您的技术向导,我将…...

衡山派D133EBS 开发环境安装及SDK编译烧写镜像烧录

1.创建新文件夹,用来存放SDK包(其实本质就是路径要对就ok了),右键鼠标通过Open Git Bash here来打开git 输入命令 git clone --depth1 https://gitee.com/lcsc/luban-lite.git 来拉取,如下所示:&#xff0…...

【Spring MVC】如何获取cookie/session以及响应@RestController的理解,Header的设置

前言 🌟🌟本期讲解关于SpringMVC的编程之参数传递~~~ 🌈感兴趣的小伙伴看一看小编主页:GGBondlctrl-CSDN博客 🔥 你的点赞就是小编不断更新的最大动力 🎆那么废…...

C++设计模式行为模式———策略模式

文章目录 一、引言二、策略模式三、总结 一、引言 策略模式是一种行为设计模式, 它能让你定义一系列算法, 并将每种算法分别放入独立的类中, 以使算法的对象能够相互替换。与模板方法模式类似,都是以扩展的方式来支持未来的变化。…...

Spring Cloud 中 bootstrap.yml 配置文件详解

Spring Cloud 中 bootstrap.yml 配置文件详解 1. 什么是 bootstrap.yml? bootstrap.yml 是 Spring Cloud 提供的一个特殊配置文件,主要用于初始化 Spring Cloud 应用程序的环境。与常见的 application.yml 不同,bootstrap.yml 在 Spring 应用…...

Java项目实战II基于SpringBoot前后端分离的网吧管理系统(开发文档+数据库+源码)

目录 一、前言 二、技术介绍 三、系统实现 四、核心代码 五、源码获取 全栈码农以及毕业设计实战开发,CSDN平台Java领域新星创作者,专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 随着互联网技术的不断发展…...

ASP网络安全讲述

一 前言   Microsoft Active Server Pages(ASP)是服务器端脚本编写环境,使用它可以创建和运行动态、交互的 Web 服务器应用程序。使用 ASP 可以组合 HTML 页 、脚本命令和 ActiveX 组件以创建交互的 Web 页和基于 Web 的功能强大的应用程序…...

DFS 创建分级菜单

菜单级别不确定&#xff0c;想要自适应&#xff0c;且可以折叠的菜单。 数据是一个数组。 <template><div class"Level" ref"Level"></div> </template>import {ref} from vue export default{data(){Level:ref(null),menuData…...

保姆级教程:在ArcGIS Pro插件中集成你的自定义工具箱(以‘消除重复要素’为例)

从脚本到按钮&#xff1a;ArcGIS Pro插件开发实战指南 在GIS日常工作中&#xff0c;我们常常会遇到一些重复性的数据处理任务。比如数据质检环节的"消除重复要素"操作&#xff0c;虽然可以通过Python脚本实现&#xff0c;但每次都需要打开IDE或Python窗口执行代码&am…...

SwitchyOmega+Burp无感抓包实战:解决HTTPS拦截与流量路由难题

1. 为什么“无感抓包”是BurpSuite日常使用的分水岭刚接触Web安全测试的朋友常有个错觉&#xff1a;装上Burp Suite&#xff0c;配好代理&#xff0c;打开浏览器&#xff0c;点几下网页——流量就该自动进来了。结果现实是&#xff1a;首页打不开、登录态丢失、HTTPS报错满屏、…...

浅聊26上半年软考架构师

2026年上半年架构师考试已然落幕&#xff0c;大家都考的如何&#xff1f;架构师共有三门考试&#xff0c;上午综合知识&#xff08;75道选择题&#xff09;案例分析&#xff0c;时间为8.30-12.30&#xff1b;下午论文&#xff0c;时间为14.30-16.30。下面说说我整体的备考过程。…...

别再乱算相似度了!用Python实战二元变量聚类:从Jaccard系数到病人分组

医疗数据分析实战&#xff1a;用Python实现基于Jaccard系数的病人症状聚类在医疗数据分析领域&#xff0c;如何从海量病人症状数据中发现潜在规律一直是临床研究的难点。传统方法往往依赖医生经验或简单统计&#xff0c;而现代数据挖掘技术为我们提供了更科学的解决方案。本文将…...

如何在macOS上免费解锁QQ音乐加密文件:完整指南

如何在macOS上免费解锁QQ音乐加密文件&#xff1a;完整指南 【免费下载链接】QMCDecode QQ音乐QMC格式转换为普通格式(qmcflac转flac&#xff0c;qmc0,qmc3转mp3, mflac,mflac0等转flac)&#xff0c;仅支持macOS&#xff0c;可自动识别到QQ音乐下载目录&#xff0c;默认转换结果…...

量子软件测试的挑战与优化策略

1. 量子软件测试的挑战与机遇量子计算正在从实验室走向实际应用&#xff0c;随之而来的是对可靠量子软件的需求激增。与传统软件不同&#xff0c;量子程序面临三大独特挑战&#xff1a;首先&#xff0c;量子态的叠加性和纠缠性使得测试变得异常复杂。一个n量子比特系统可以同时…...

ROS Noetic实战:从bag包里‘抠’出雷达点云和IMU数据的保姆级教程(Ubuntu 20.04)

ROS Noetic实战&#xff1a;从bag包里提取雷达点云和IMU数据的完整指南&#xff08;Ubuntu 20.04&#xff09;在机器人开发中&#xff0c;ROS bag文件就像是一个装满珍贵数据的宝箱&#xff0c;而雷达点云和IMU数据则是其中最闪亮的宝石。作为一名长期与ROS打交道的开发者&…...

天文时序数据分析:机器学习评估、半监督学习与无监督方法实战

1. 项目概述&#xff1a;当机器学习遇见星空 处理海量的天文时序数据&#xff0c;比如来自Kepler、TESS这些“巡天巨眼”的光变曲线&#xff0c;早已不是靠人眼一张张图去翻的时代了。数据量太大&#xff0c;噪声复杂&#xff0c;信号微弱&#xff0c;传统方法常常力不从心。这…...

GEP协议深度解读:AI智能体自我进化的基因工程

OpenAI 官宣全面支持MCP协议,标志着AI应用架构的"连接标准"已定。如果说MCP是AI时代的USB-C,解决了模型与工具的连接问题,那么GEP(Genome Evolution Protocol,基因组进化协议)则正在解决另一个更本质的问题——智能体的自我进化与生命周期管理。 作为下一代AI基…...

JMeter实现RSA签名验签全流程实战

1. 为什么RSA加密接口测试总卡在“连通但失败”这一步&#xff1f; 你有没有遇到过这种情况&#xff1a;接口文档写得清清楚楚&#xff0c;Postman里填好URL、Header、Body&#xff0c;一发请求——返回 {"code":4001,"msg":"签名验证失败"} …...