C#中的反射(Reflection)使用经典案例

news2025/2/27 9:37:42

文章目录

      • 1. 动态加载和调用类的方法
      • 2. 记录用户修改行为
      • 3. 调用私有构造函数
      • 4. 泛型类型的动态创建和使用
      • 5. 动态类型转换与检查
      • 6. 获取和设置私有、受保护成员
      • 7. 枚举程序集、模块、类型等信息
      • 8. 处理泛型类型参数
      • 9. 动态生成代码或动态编译
      • 10. 配置驱动的应用程序扩展
      • 注意事项:

C#中的反射(Reflection)是.NET框架提供的一种强大的运行时元编程机制,它允许程序在运行时获取类型信息、创建对象实例、调用方法、访问字段和属性等,而这些操作在编译时可能是未知的。以下是几个使用反射的典型场景:

1. 动态加载和调用类的方法

假设有一个库包含多个实现了同一接口的类,用户可以通过配置文件指定要使用的具体类名和方法名。通过反射,可以在运行时根据配置加载相应的类型,并调用指定的方法。

// 假设有个接口和其实现类
public interface ICalculator
{
    int Calculate(int a, int b);
}

public class Adder : ICalculator
{
    public int Calculate(int a, int b) => a + b;
}

// 配置中读取类名
string className = "Adder";
Type calculatorType = Type.GetType(className);

// 创建实例并调用方法
ICalculator calculator = (ICalculator)Activator.CreateInstance(calculatorType);
int result = calculator.Calculate(3, 5);

2. 记录用户修改行为

如您提到的应用场景,系统需要记录用户修改了哪个实体类的哪些字段。通过反射,可以遍历实体类的所有属性,在用户修改后记录下变化的属性名和新旧值。

public class User
{
    public string Name { get; set; }
    public int Age { get; set; }
    // 其他属性...
}

// 用户更新了一个User实例
var user = new User { Name = "OldName", Age = 30 };

foreach (var property in properties)
{
    // 获取旧值(假设这是更改前的值)
    var oldValue = property.GetValue(user);

    // 模拟用户更改属性值
    if (property.Name == "Name")
    {
        user.Name = "NewName";
    }

    // 再次获取新值
    var currentValue = property.GetValue(user);

    // 如果旧值与当前值不相等,则记录变更
    if (!object.Equals(oldValue, currentValue) && property.CanRead && property.CanWrite)
    {
        LogChange(property.Name, oldValue, currentValue);
    }
}

3. 调用私有构造函数

反射还可以用来调用非公开的构造函数,比如破坏单例模式时可能会用到:

public sealed class Singleton
{
    private static readonly Singleton instance = new Singleton();

    private Singleton() { }

    public static Singleton Instance => instance;

    // 通过反射破坏单例模式
    public static Singleton CreateAnotherInstance()
    {
        ConstructorInfo ctor = typeof(Singleton).GetConstructor(
            BindingFlags.Instance | BindingFlags.NonPublic,
            null, Type.EmptyTypes, null);
        return (Singleton)ctor.Invoke(null);
    }
}

4. 泛型类型的动态创建和使用

反射结合泛型,可以实现在不知道具体类型参数的情况下动态创建泛型类型实例:

public class GenericClass<T>
{
    public T Value { get; set; }
}

Type genericType = typeof(GenericClass<>).MakeGenericType(typeof(string));
dynamic instance = Activator.CreateInstance(genericType);
instance.Value = "Hello, World!";

C#反射除了上述提到的几个典型应用场景外,还有以下一些常见的用途:

5. 动态类型转换与检查

  • 判断一个对象是否实现了某个接口或继承自某个类。
  • 在不知道具体类型的情况下,将对象动态转换为指定类型。
object obj = new MyDerivedClass();
Type type = obj.GetType();

// 检查类型是否实现了某个接口
bool isDisposable = typeof(IDisposable).IsAssignableFrom(type);

// 动态转换
if (type == typeof(MyDerivedClass))
{
    MyDerivedClass derivedObj = (MyDerivedClass)obj;
    // 使用转换后的对象...
}

6. 获取和设置私有、受保护成员

  • 反射可以访问私有字段、属性和方法,这在测试框架中特别有用,可以模拟对私有成员的调用或者验证其值。
public class MyClass
{
    private int myPrivateField;
    
    public void SetPrivateValue(int value)
    {
        this.myPrivateField = value;
    }
}

var instance = new MyClass();
FieldInfo field = typeof(MyClass).GetField("myPrivateField", BindingFlags.NonPublic | BindingFlags.Instance);
field.SetValue(instance, 42);  // 设置私有字段值

int fieldValue = (int)field.GetValue(instance);  // 获取私有字段值

7. 枚举程序集、模块、类型等信息

  • 在大型应用程序中,可能需要枚举整个程序集中所有类型的元数据信息,比如获取所有的类名、特性(Attributes)等。
Assembly assembly = Assembly.GetExecutingAssembly();
foreach (Type type in assembly.GetTypes())
{
    Console.WriteLine($"Type: {type.FullName}");

    foreach (Attribute attribute in Attribute.GetCustomAttributes(type))
    {
        Console.WriteLine($"  Attribute: {attribute.GetType().Name}");
    }
}

8. 处理泛型类型参数

  • 反射可以帮助获取泛型类型的具体参数类型,并据此创建特定类型的实例。

9. 动态生成代码或动态编译

  • .NET Framework 和 .NET Core 提供了 System.Reflection.Emit 命名空间,允许开发者在运行时动态生成类型和方法。这对于实现AOP(面向切面编程)、动态代理或其他高级编程技术非常有用。

10. 配置驱动的应用程序扩展

  • 反射常用于构建插件式架构,根据配置文件加载不同插件(DLL)并在运行时动态加载并执行插件中的代码。

总之,C#反射是一个强大的工具,它允许程序在运行时获得关于类型和程序集的信息,并基于这些信息进行操作,极大地增强了应用程序的灵活性和适应性。但需要注意的是,过度使用反射可能会降低性能,应谨慎权衡其带来的便利性和潜在的成本。

注意事项:

  • 反射通常会带来性能开销,因为它涉及到运行时类型查找和动态方法调用。
  • 安全性方面,过度依赖反射可能导致代码容易受到攻击,例如绕过私有成员保护机制。
  • 静态编译优化对反射调用可能不适用,因此在对性能敏感的场合应谨慎使用反射。

python推荐学习汇总连接:
50个开发必备的Python经典脚本(1-10)

50个开发必备的Python经典脚本(11-20)

50个开发必备的Python经典脚本(21-30)

50个开发必备的Python经典脚本(31-40)

50个开发必备的Python经典脚本(41-50)
————————————————

​最后我们放松一下眼睛
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

粒子群算法优化RBF神经网络回归分析

目录 完整代码和数据下载链接:粒子群算法优化RBF神经网络回归分析(代码完整,数据齐全)资源-CSDN文库 https://download.csdn.net/download/abc991835105/88738570 RBF的详细原理 RBF的定义 RBF理论 易错及常见问题 RBF应用实例,基于rbf的空调功率预测 代码 结果分析 展望…

动态规划篇-03:打家劫舍

198、打家劫舍 状态转移方程 base case 边界问题就是&#xff1a;走到最后一间房子门口也没抢&#xff0c;那么最终抢到的金额为0 明确状态 “原问题和子问题中会变化的变量” 抢到的金额数就是状态&#xff0c;因为随着在每一件房子门口做选择&#xff0c;抢到的金额数会随…

Springboot3新特性:开发第一个 GraalVM 本机应用程序(完整教程)

在讲述之前&#xff0c;各位先自行在网上下载并安装Visual Studio 2022&#xff0c;安装的时候别忘了勾选msvc 概述&#xff1a;GraalVM 本机应用程序&#xff08;Native Image&#xff09;是使用 GraalVM 的一个特性&#xff0c;允许将 Java 应用程序编译成本机二进制文件&am…

VS2019中解决一些配置问题

一、取消一堆冗余的C语法告警 1.点击项目最下面的属性栏 2.选择代码分析&#xff0c;点击常规&#xff0c;将其中的设置全部改为否&#xff0c;确定即可

GRE隧道(初级VPN)配置步骤

一、拓朴图&#xff1a; 二、配置步骤&#xff1a; 1、配置IP 2、R1、R2 配置nat&#xff0c;代理内网地址通过G0/0/0口上外网 acl 2000rule permit source anyquit # int G0/0/0ip addr 100.1.1.1 24nat outbound 2000 # 3、R1、R2 配置默认出口路由G0/0/0&#xff0c;这一…

【开源】基于JAVA+Vue+SpringBoot的桃花峪滑雪场租赁系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 游客服务2.2 雪场管理 三、数据库设计3.1 教练表3.2 教练聘请表3.3 押金规则表3.4 器材表3.5 滑雪场表3.7 售票表3.8 器材损坏表 四、系统展示五、核心代码5.1 查询教练5.2 教练聘请5.3 查询滑雪场5.4 滑雪场预定5.5 新…

高斯Hack算法

背景 刷leetcode时&#xff0c;碰到一题需要求解n个bit中选择m个bit的所有组合集&#xff0c;我只想到了递归求解&#xff0c;没啥问题&#xff0c;但是在官方题解中看到了牛逼的方法(Gospers Hack)&#xff0c;故记录一下。 4bit中2个1的情况 0011b0101b0110b1001b1010b1100b…

第 380 场周赛 解题报告 | 珂学家 | 数位DP 二分 + 字符串Hash

前言 整体评价 感觉T3更难些&#xff0c;T4太直接了&#xff0c;一般的KMP/StringHash基本就够用了。 上周T4出数位DP&#xff0c;估计是为T3打了一个铺垫。 A. 最大频率元素计数 思路: 模拟即可 class Solution {public int maxFrequencyElements(int[] nums) {Map<Int…

Day29 131分割回文串 93复原ip地址

131分割回文串 给定一个字符串 s&#xff0c;将 s 分割成一些子串&#xff0c;使每个子串都是回文串。 返回 s 所有可能的分割方案。 示例: 输入: "aab" 输出: [ ["aa","b"], ["a","a","b"] ] class Solution …

大数据深度学习卷积神经网络CNN:CNN结构、训练与优化一文全解

文章目录 大数据深度学习卷积神经网络CNN&#xff1a;CNN结构、训练与优化一文全解一、引言1.1 背景和重要性1.2 卷积神经网络概述 二、卷积神经网络层介绍2.1 卷积操作卷积核与特征映射卷积核大小多通道卷积 步长与填充步长填充 空洞卷积&#xff08;Dilated Convolution&…

ST工具Flash Loader烧写STM32

简介 使用ST公司自家的Flash Loader烧写程序&#xff0c; 如下图, F103直接接USART1到PC端就好, 使用普通的USB转TTL线&#xff0c; 就是你之前使用串口打印的方式连接到电脑就好。 软件下载 ST Flash Loader 我放到CSDN里面了Flash_Loader_demo_v2.8.0 开发板设置 Boot0-&g…

泊松流生成模型简介

一、说明 泊松流生成模型 (PFGM) 是一种新型的生成深度学习模型&#xff0c;与扩散模型类似&#xff0c;其灵感来自物理学。在这本简单易懂的指南中了解 PFGM 背后的理论以及如何使用它们生成图像。 生成式人工智能模型在过去几年中取得了长足的进步。受物理启发的扩散…

别再用老掉牙的技术了!试试微服务架构!从零教你认识、开发、部署微服务

从0带你认识、开发、部署微服务&#xff08;一&#xff09; 1.认识微服务 随着互联网行业的发展&#xff0c;对服务的要求也越来越高&#xff0c;服务架构也从单体架构逐渐演变为现在流行的微服务架构。这些架构之间有怎样的差别呢&#xff1f; 1.0.目标 微服务架构的优缺点…

Spring Boot 3 + Vue 3实战:实现用户登录功能

文章目录 一、实战概述二、实战步骤​&#xff08;一&#xff09;创建后端项目1、创建Spring Boot项目2、启动应用&#xff0c;访问首页 &#xff08;二&#xff09;创建前端项目1、创建Vue项目2、安装axios模块3、安装vue-router模块4、安装less和less-loader模块5、运行Vue项…

远程开发之端口转发

远程开发之端口转发 涉及的软件forwarded port 通过端口转发&#xff0c;实现在本地电脑上访问远程服务器上的内网的服务。 涉及的软件 vscode、ssh forwarded port 在ports界面中的port字段&#xff0c;填需要转发的IP:PORT&#xff0c;即可转发远程服务器中的内网端口到本…

LeetCode刷题(ACM模式)-05栈与队列

参考引用&#xff1a;代码随想录 注&#xff1a;每道 LeetCode 题目都使用 ACM 代码模式&#xff0c;可直接在本地运行&#xff0c;蓝色字体为题目超链接 0. 栈与队列理论基础 21天学通C读书笔记&#xff08;二十三&#xff1a;自适应容器&#xff1a;栈和队列&#xff09; 堆…

Bean作用域及生命周期

关于Bean对象&#xff0c;在将其存储到spring中以后&#xff0c;在使用或读取该Bean对象时&#xff0c;如果该对象是公有的&#xff0c;难免就会出现被一方修改&#xff0c;从而影响另外一方读取到的对象准确性的情况。因此了解Bean的作用域和生命周期就是十分必要的了。 首先…

一、MySQL 卸载

目录 1、软件的卸载准备 2、软件的卸载 方式一&#xff1a;通过控制面板卸载 方式二&#xff1a;通过mysql8的安装向导卸载 1、双击mysql8的安装向导 2、取消更新 3、选择要卸载的mysql服务器软件的具体版本 4、确认删除数据目录 5、执行删除 6、完成删除 3、清理残…

Springboot中使用Filter过滤器

1、概述 springboot工程中使用Filter过滤器与其他地方使用基本相同&#xff0c;只是注入的方式不同。 2、创建Filter过滤器 实现Filter接口&#xff0c;重写doFilter方法 filterChain.doFilter(servletRequest,servletResponse);表示放行 public class MyFilter implement…

Python字符串验证与正则表达式【第23篇—python基础】

文章目录 引言方法1&#xff1a;使用 isalpha() 方法方法2&#xff1a;使用正则表达式方法3&#xff1a;遍历字符检查应用场景示例与比较优化与扩展方法4&#xff1a;考虑空格和其他字符应用场景扩展 示例与比较优化与扩展方法4&#xff1a;考虑空格和其他字符方法5&#xff1a…