GetProperty 安全获取属性值需显式指定 BindingFlags,如 Public | Instance;GetValue 前须确保 obj 类型匹配 DeclaringType 且静态/实例调用正确。

怎么用 GetProperty 安全拿到属性值
直接调用 GetProperty 但返回 null,八成是没考虑绑定标志。C# 反射默认只查 public 实例成员,private、static、继承来的属性都得手动指定 BindingFlags。
常见错误现象:GetProperty("Name") 返回 null,但类里明明有 public string Name { get; set; } —— 很可能对象是 null,或者传的是基类类型却在子类上定义了该属性。
- 必须显式传
BindingFlags.Public | BindingFlags.Instance才能查 public 实例属性 - 要访问 private 属性,加
BindingFlags.NonPublic;要查静态属性,加BindingFlags.Static - 如果属性在基类,但用子类类型调用
GetProperty,默认能查到;但如果用typeof(BaseClass).GetProperty(...)查子类特有属性,就一定为null - 推荐写法:
type.GetProperty("Name", BindingFlags.Public | BindingFlags.Instance),不依赖默认行为
GetValue 报错 “Object does not match target type” 怎么办
这个错误不是因为值为空,而是传给 GetValue 的第一个参数(obj)类型和属性声明类型不匹配。典型场景:你拿 typeof(Derived).GetProperty("X") 得到属性,却把 new Base() 传给它的 GetValue。
另一个高发场景:属性是 static,但你传了实例对象——这时应传 null;反过来,实例属性传 null 也会崩。
- 检查
PropertyInfo.DeclaringType和你传入的obj的实际运行时类型是否兼容 - static 属性:调用
prop.GetValue(null) - 实例属性:确保
obj不为null,且是prop.DeclaringType或其子类的实例 - 如果不确定,先用
prop.CanRead判断可读性,再用prop.GetMethod?.IsStatic判断是否静态
动态调用方法比属性更危险?GetMethod + Invoke 的坑
属性至少有明确的 get/set 签名,方法参数多、重载多、ref/out 处理难,Invoke 一错就抛异常,而且错误信息往往不指明具体哪参数错了。
最常踩的坑是参数数组类型不匹配:比如方法签名是 void M(int x, string y),你传 new object[] { 42, null },看着没问题,但如果 y 是 string? 且目标框架是 .NET 5+,null 没问题;但在 .NET Framework 下某些场景会因类型推导失败而报 TargetParameterCountException。
- 永远用
GetMethod("M", new[] { typeof(int), typeof(string) })显式指定参数类型,别依赖GetMethods()后遍历匹配 - 遇到
ref或out参数,必须传对应类型的变量地址(即用ref修饰的局部变量),不能传字面量或临时对象 - 性能敏感路径避免反复调用
GetMethod,缓存MethodInfo实例;但注意泛型方法需按具体封闭类型缓存 - 若方法可能 throw,别指望反射层帮你吞异常——
Invoke抛出的是TargetInvocationException,真实异常藏在.InnerException
为什么 GetProperty 找不到自动属性的 backing field
自动属性(如 public string Name { get; set; })的 backing field 是编译器生成的私有字段,名字形如 <name>k__BackingField</name>,但这个名字不是规范,不同编译器、不同版本可能不同,甚至同一版本下启用优化后也可能被内联掉。
所以别试图用反射去“找字段”来绕过属性逻辑——它不稳定、不可靠、不跨平台。如果你真需要绕过属性 setter 的验证逻辑(比如反序列化时设只读属性),正确做法是用 PropertyInfo.SetValue(obj, value, null) 配合 BindingFlags.NonPublic 获取 property 本身,而不是去找字段。
- 字段名是实现细节,
GetField("<name>k__BackingField")</name>在 .NET Core/.NET 5+ 中大概率失败 - 即使侥幸拿到字段,对
init属性或带required的字段,绕过 property 仍可能破坏对象不变性 - 真正需要字段级操作的场景(如 deep clone、ORM 映射),应使用
Expression编译委托或专用库(如FastMember),而非硬编码字段名
反射不是万能胶,它暴露的是元数据契约,不是内存布局。越想钻得深,越容易撞上编译器和运行时的边界。


















