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

跟着AI学习C# Day27

📅 Day 27:C# 中的反射(Reflection)与元编程

✅ 学习目标:

  • 理解什么是 反射(Reflection)
  • 掌握如何在运行时动态获取类型信息、创建实例、调用方法;
  • 使用反射实现通用逻辑(如对象克隆、属性赋值等);
  • 理解反射在框架开发中的典型应用(依赖注入、序列化、ORM);
  • 了解 System.Reflection.Emit 实现动态代码生成;
  • 掌握性能优化技巧(缓存反射结果、使用表达式树代替 Invoke);
  • 编写一个基于反射的通用对象克隆器。

🧠 一、什么是反射?

反射(Reflection) 是 .NET 提供的一种机制,允许你在运行时查看程序集(Assembly)中的类型信息,并动态创建对象、访问成员、调用方法等。

主要用途:

场景示例
动态加载程序集插件系统、模块化架构
获取类型信息查看类、接口、方法、属性等
创建实例和调用方法工厂模式、依赖注入容器
属性操作数据绑定、ORM 映射
自定义特性解析验证模型、权限控制
表达式树构建构建 LINQ 查询、动态条件过滤

🔍 二、基本反射操作

1️⃣ 获取类型信息

Type type = typeof(string);
Console.WriteLine("类型名称:" + type.FullName);

或通过对象获取:

Person person = new Person();
Type type = person.GetType();

2️⃣ 获取构造函数并创建实例

Type type = typeof(Person);
object obj = Activator.CreateInstance(type);

指定参数:

object obj = Activator.CreateInstance(type, "张三", 25);

3️⃣ 获取方法并调用

MethodInfo method = type.GetMethod("SayHello");
method.Invoke(obj, null);

带参数的方法:

MethodInfo method = type.GetMethod("SetName", new[] { typeof(string) });
method.Invoke(obj, new object[] { "李四" });

4️⃣ 获取属性并读取/设置值

PropertyInfo prop = type.GetProperty("Name");
string name = (string)prop.GetValue(obj);
prop.SetValue(obj, "王五");

5️⃣ 获取字段并操作

FieldInfo field = type.GetField("_age", BindingFlags.NonPublic | BindingFlags.Instance);
field.SetValue(obj, 30);
int age = (int)field.GetValue(obj);

💡 三、反射的应用场景

应用反射的作用
ORM 框架(如 EF Core)将数据库记录映射为实体对象
JSON 序列化(如 Newtonsoft.Json)读取对象属性并转换为 JSON 字符串
依赖注入容器根据配置自动解析服务和依赖
单元测试框架(xUnit/NUnit)找到所有测试方法并执行
MVC/Web API 框架路由匹配、Action 方法调用
插件系统动态加载 DLL 并调用其中的方法

🧱 四、Expression 替代反射提高性能

反射虽然强大,但性能较低。可以通过 表达式树(Expression Tree)委托缓存 来优化。

示例:构建属性访问委托

public static Func<T, string> CreatePropertyGetter<T>(string propertyName)
{ParameterExpression param = Expression.Parameter(typeof(T));MemberExpression property = Expression.Property(param, propertyName);UnaryExpression cast = Expression.Convert(property, typeof(string));return Expression.Lambda<Func<T, string>>(cast, param).Compile();
}
使用:
var getter = CreatePropertyGetter<Person>("Name");
Person p = new Person { Name = "Tom" };
Console.WriteLine(getter(p));  // 输出 Tom

🧩 五、动态代码生成(System.Reflection.Emit)

你可以使用 System.Reflection.Emit 在运行时生成新的类型和方法,用于高性能场景(如 AOP、代理类生成、动态编译)。

示例:动态创建一个类并调用方法

AssemblyName assemblyName = new AssemblyName("DynamicAssembly");
AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");TypeBuilder typeBuilder = moduleBuilder.DefineType("MyDynamicClass", TypeAttributes.Public);
MethodBuilder methodBuilder = typeBuilder.DefineMethod("SayHello",MethodAttributes.Public | MethodAttributes.Static,typeof(void),Type.EmptyTypes);ILGenerator il = methodBuilder.GetILGenerator();
il.EmitWriteLine("Hello from dynamic class!");
il.Emit(OpCodes.Ret);Type dynamicType = typeBuilder.CreateType();
MethodInfo method = dynamicType.GetMethod("SayHello");
method.Invoke(null, null);  // 输出:Hello from dynamic class!

💪 六、实战练习:通用对象克隆器

功能要求:

  • 支持任意类型的对象深拷贝;
  • 使用反射复制所有公共属性;
  • 忽略只读属性;
  • 返回新实例。
示例代码:
public static T Clone<T>(T source) where T : class, new()
{if (source == null) return null;T target = new T();foreach (PropertyInfo prop in typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance)){if (!prop.CanRead || !prop.CanWrite) continue;object value = prop.GetValue(source);prop.SetValue(target, value);}return target;
}
使用示例:
Person original = new Person { Name = "Alice", Age = 30 };
Person copy = Clone(original);

⚡ 七、性能优化建议

技术说明
缓存 MethodInfo / PropertyInfo避免重复反射查询
使用委托替代 Invoke性能提升可达几十倍
使用 Expression Tree 构建委托更安全、更高效
使用 System.Runtime.CompilerServices.Unsafe高性能场景下直接操作内存
使用 Source Generator(C# 9+)在编译期生成代码,避免运行时反射

📝 小结

今天你学会了:

  • 什么是反射及其作用;
  • 如何在运行时获取类型信息、创建实例、调用方法;
  • 掌握了反射在框架开发中的典型应用场景;
  • 学会了使用表达式树优化反射性能;
  • 了解了 System.Reflection.Emit 实现动态代码生成;
  • 编写了一个基于反射的通用对象克隆器;
  • 掌握了多种反射性能优化技巧。

反射是 C# 强大而灵活的特性之一,尤其适用于构建插件系统、ORM、序列化库、AOP 等高级框架。


🧩 下一步学习方向(Day 28)

明天我们将进入一个新的主题 —— C# 中的源生成器(Source Generators)与编译时元编程,你将学会:

  • 什么是源生成器(Source Generator);
  • 如何在编译阶段生成 C# 代码;
  • 使用源生成器替代运行时反射;
  • 构建高性能、零运行时开销的实用工具;
  • 实现一个基于源生成器的自动化 DTO 映射器;
  • 掌握 Roslyn 编译器扩展的基本原理。
http://www.xdnf.cn/news/1062631.html

相关文章:

  • 华为云Flexus+DeepSeek征文|基于华为云一键部署Dify LLM 应用构建 PPT 生成助手的开发与实践
  • 力扣-72.编辑距离
  • 构建高效智能体系统:从简单到复杂,找到最适合你的解决方案
  • 3D可视化数字孪生智能服务平台-物联网智控节能控、管、维一体化技术架构
  • Gartner《AI-Driven Methods for Cost-Efficiency》学习心得
  • 类图:软件世界的“建筑蓝图”
  • 【Python】List
  • 结构体的嵌套问题
  • FPGA基础 -- Verilog 的属性(Attributes)
  • python+uniapp基于微信小程序的高校二手商品交易系统
  • Maven并行构建
  • 饼图:数据可视化的“切蛋糕”艺术
  • 大数据治理域——计算管理
  • windows清理系统备份文件夹WinSxS文件夹清理
  • 大数据Hadoop集群搭建
  • mysql server层做了什么
  • nginx的下载与安装 mac
  • 三种经典算法无人机三维路径规划对比(SMA、HHO、GWO三种算法),Matlab代码实现
  • 【Python】Excel表格操作:ISBN转条形码
  • RPC常见问题回答
  • Qwen3 Embedding 结构-加载-训练 看透模型设计哲学
  • windows查看占用端口的进程并杀死进程
  • phpstudy无法启动apache,80端口被占用,完美解决
  • 【MySQL篇10】:四种分库分表详解
  • Symbol.iterator 详解
  • Windows 10 防火墙 0x8007045b 打不开
  • Rust 项目文档生成之旅:cargo doc
  • 博士,超28岁,出局!
  • MySQL复杂查询优化实战:从多表关联到子查询的性能突破
  • 掌握Bash脚本编写:从服务启动脚本到语法精要