反射需谨慎使用:优先用typeof而非gettype(),获取私有成员需bindingflags.nonpublic,自动属性应通过getproperty而非getfield,方法调用须精准匹配参数类型,高频场景应缓存constructorinfo或用表达式树优化。

反射不是万能的,但不用它,很多动态场景根本跑不起来——关键在于别在热路径上滥用 GetType() 和 GetField(),也别指望靠它绕过访问修饰符做“黑盒操作”。
怎么安全地获取类的公开成员信息
用 typeof(MyClass) 比 obj.GetType() 更快、更确定,尤其当你已知类型时。如果对象可能为 null,又必须用实例获取类型,先判空再调用,否则抛 NullReferenceException。
获取字段/属性时,默认只返回 public 成员。要读私有字段?得显式传 BindingFlags.NonPublic | BindingFlags.Instance,而且仅限当前程序集内——跨程序集的 private 成员反射失败是常态,不是 bug。
-
type.GetFields()只返回字段(field),不含自动属性背后的 backing field(C# 编译器生成的<propname>k__BackingField</propname>) - 要拿到自动属性值,用
type.GetProperty("Name")?.GetValue(obj),别试图用GetField()去找编译器生成的字段名 - 属性有 getter 但无 setter?
PropertyInfo.CanWrite为false,强行SetValue()会抛ArgumentException
调用方法前必须确认的三件事
反射调用方法最常卡在参数类型不匹配。C# 的重载机制在运行时不会帮你推导,GetMethod("Save") 可能返回多个结果,必须用参数类型数组精准定位:
var method = type.GetMethod("Process", new[] { typeof(string), typeof(int) });
没找到?检查大小写(C# 区分大小写)、是否是泛型方法(需先调用 MakeGenericMethod())、是否被标记为 internal(跨程序集需加 BindingFlags.NonPublic)。
- 静态方法:调用
method.Invoke(null, args),第一个参数传null - 实例方法:第一个参数必须是目标实例,不能是
null(除非是静态方法) - 方法抛异常?反射层包装成
TargetInvocationException,原始异常在.InnerException里,别直接吞掉
为什么 Activator.CreateInstance() 有时比 new 快,有时慢十倍
对无参构造函数,Activator.CreateInstance<t>()</t> 经过 JIT 优化后几乎和 new T() 一样快;但带参数或泛型约束时,它会走完整反射流程,性能差距明显。
高频创建对象(如 ORM 映射循环)务必缓存 ConstructorInfo 或改用表达式树编译委托——下面这行代码执行一次后,后续调用就是纯委托调用,不走反射:
var ctor = typeof(MyClass).GetConstructor(new[] { typeof(string) });<br>var factory = Expression.Lambda(Expression.New(ctor, Expression.Parameter(typeof(string)))).Compile();
-
Activator.CreateInstance(Type, object[])要求参数顺序、类型完全匹配,不支持命名参数或可选参数 - 构造函数抛异常?同样封装为
TargetInvocationException,且InnerException才是真实错误 - 结构体(
struct)也能用Activator.CreateInstance(),但默认值初始化推荐直接用default(T),更快更安全
真正难的不是怎么写反射代码,而是判断“这里到底该不该用反射”。比如配置绑定、插件加载、序列化——这些是合理场景;而用来规避设计缺陷、替代接口抽象、或者反复读同一个私有字段——这些迟早变成技术债。










