反射本质是读取程序集元数据而非反编译,用于运行时获取类型信息和动态调用,但性能开销大(如Invoke慢20–100倍),适用于插件、ORM、序列化等解耦场景,需避免滥用引发隐式依赖风险。
C# 反射不是“黑魔法”,而是对程序集元数据的读取和操作能力——它能让你在运行时知道一个类型长什么样、有哪些方法、怎么创建实例,但代价是明确的性能开销。
你写的 C# 代码编译后会生成 .dll 或 .exe 文件,里面除了中间语言(MSIL),还有一块叫「元数据」的二进制区域。它像一张静态说明书,记录了所有类名、方法签名、属性、字段、构造函数、特性(Attribute)等信息

反射(System.Reflection)干的事,就是按需打开这张说明书,查表、解析、调用——它不执行反编译,也不还原源码,只读元数据。
private” —— 实际上只能访问 private 成员是因为 BindingFlags.NonPublic 允许你“翻说明书里的隐藏条目”,不是突破访问限制Activator.CreateInstance 和 MethodInfo.Invoke 是性能重灾区反射慢,主要慢在这两个环节:它们要走完整的“查找 → 绑定 → 安全检查 → 调用”链路,而直接 new 或方法调用是 JIT 编译后的一条机器指令。
Activator.CreateInstance(typeof(MyClass)) 比 new MyClass() 慢 5–10 倍(无参构造);带参构造更慢,尤其参数类型匹配失败时还会抛异常methodInfo.Invoke(obj, args) 比直接调用慢 20–100 倍,取决于参数数量和是否需要装箱/拆箱ConstructorInfo / MethodInfo 实例;或用 Expression.Lambda 编译成委托(一次编译,多次调用接近原生速度)反射不是通用工具,它是为特定解耦场景设计的——当编译时完全不知道类型,又必须在运行时跟它打交道时,才值得引入。
Plugin.dll,通过约定接口名(如 ICommand)查找并实例化实现类Dapper / EF Core 用反射读取实体类的 PropertyInfo,把数据库字段映射到对象属性Newtonsoft.Json 用反射遍历属性生成 JSON 字符串Enum.Parse 就够了,不需要 Type.GetType(...).GetMethod(...).Invoke(...)
真正该警惕的,不是“反射慢”,而是“反射让调用关系脱离代码可见性”——你改了一个私有字段名,编译器不报错,但某处反射代码就默默挂了。这种隐式依赖,比性能更难维护。