type 是获取类型元数据的入口,而非直接操作类型的工具;需配合 bindingflags、activator、methodinfo 等机制才能安全执行反射操作,任一环节缺失将导致静默失败或异常。

直接说结论:Type 不是“用”出来的类型,而是你**获取类型元数据的入口**;真正要操作对象、调用方法、读写字段,必须配合 BindingFlags、Activator、MethodInfo 等配套机制——漏掉任意一环,代码就静默失败或抛异常。
typeof、GetType、Type.GetType 三者怎么选
这不是风格问题,是运行时机和可靠性差异:
-
typeof(string):编译期已知类型,性能最高,但只能写死类型名;写typeof(MyClass)而类不存在 → 编译报错 -
obj.GetType():运行时靠实例反推真实类型,支持多态(比如Animal a = new Dog(); a.GetType()返回Dog),但obj为null会立刻炸出NullReferenceException -
Type.GetType("MyNamespace.MyClass"):靠字符串查类型,适合插件/配置驱动场景,但必须传完整名称(含命名空间),且类型得已加载进当前Assembly;查不到就返回null,不抛异常——很多人忘了判空,后续调GetMethods()就崩
GetProperties() 返回空数组?BindingFlags 没配齐
这是最常被忽略的坑:默认只返回 public + Instance 属性,其他一律隐身。
- 要读
private字段或属性 → 加BindingFlags.NonPublic - 要读
static成员 → 加BindingFlags.Static - 要读父类公开属性(比如基类
Name)→ 加BindingFlags.FlattenHierarchy(注意:它只对public或static有效) - 漏掉
BindingFlags.Instance?哪怕属性明明是实例的,也会被过滤掉 - 正确组合示例:
BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic
MethodInfo.Invoke 报 “Object does not match target type”
错误不是因为参数不对,而是你拿 A 类型的 MethodInfo,却传了 B 类型的实例进去——哪怕 B 继承自 A,反射也认死理。
- 检查
methodInfo.DeclaringType和你传入的obj的实际类型是否一致(用obj.GetType()看) - 如果属性/方法定义在基类,别从基类
Type获取再往子类实例上硬套;直接用子类Type调GetProperties() - 值类型(
struct)要注意装箱:传GetValue()的是 struct 实例,返回的是object(已装箱),别当成引用原地修改
缓存 PropertyInfo / MethodInfo 时容易翻车的点
为了性能常把反射结果缓存起来,但缓存键设计不对,反而引入隐性 bug:
- 不能只用方法名当 key,重载方法会冲突;必须包含参数类型数组(
methodInfo.GetParameters().Select(p => p.ParameterType)) - 泛型类型要区分开放构造类型(
List)和封闭类型(List<int></int>);typeof(List<int>).GetGenericTypeDefinition()</int>才能归到同一类 - 带
BindingFlags的结果不能混用:GetProperties(BindingFlags.Public)和GetProperties(BindingFlags.Public | BindingFlags.NonPublic)返回的结果完全不同
真正难的从来不是“怎么拿到 Type”,而是拿到之后,怎么让后续每一步都稳住类型契约——尤其是跨继承、跨泛型、跨装箱场景下,DeclaringType 和运行时实例类型的微妙差异,往往只在特定数据路径上才暴露。










