如何用 typeof
和 GetType()
获取类型对象
反射的起点是拿到
Type实例。最常用两种方式:编译期已知类型用
typeof,运行时对象用
GetType()。
typeof是编译时运算符,不触发类型初始化;
GetType()是实例方法,要求对象非 null。
typeof(string)直接获取
Type,适用于你知道类型名的场景
"hello".GetType()返回
System.String,但若变量为
null会抛
NullReferenceException泛型类型需注意:
typeof(List<int>)</int>正确,
typeof(List)编译失败(缺少泛型参数) 对于值类型,
GetType()总是返回装箱后的实际运行时类型,而
typeof可直接写
typeof(int)
用 Type.GetMembers()
和 Type.GetFields()
查看成员结构
拿到
Type后,常要检查它公开了哪些字段、属性、方法。不同方法返回不同粒度的元数据,且默认只返回 public 成员,需显式传入
BindingFlags才能访问 private 或静态成员。
type.GetFields()只返回字段(
FieldInfo),不含属性;
type.GetProperties()返回属性(
PropertyInfo),不含字段 想查私有字段?必须加
BindingFlags.NonPublic | BindingFlags.Instance,否则返回空数组
type.GetMembers()是“大杂烩”,返回所有成员(字段、方法、属性、事件等),但不能直接读写值,适合做结构扫描 性能提示:这些方法每次调用都新建数组,频繁调用建议缓存结果,尤其在热路径中
通过 FieldInfo.GetValue()
和 PropertyInfo.GetValue()
读取值
反射读值的关键是区分“实例成员”和“静态成员”。对实例成员,
GetValue()第一个参数必须传入对应实例;对静态成员,传
null即可。 读取实例字段:
fieldInfo.GetValue(obj),其中
obj不能为
null(除非字段是 static) 读取属性:
propertyInfo.GetValue(obj),同样需传实例;若属性有 getter 逻辑,该逻辑会在反射调用时执行 读取静态字段或属性:第二个参数传
null,如
staticField.GetValue(null)值类型字段读取后是装箱对象,需手动
Convert.ChangeType()或
(int)val强转——但要注意
null值和可空类型(
int?)的处理,否则抛
InvalidCastException
反射调用方法时 MethodInfo.Invoke()
的常见陷阱
Invoke()看似简单,但参数传递、重载解析、异常包装这三点最容易出错。 参数必须是
object[],哪怕方法只有一个
int参数,也要写成
new object[] { 42 };传 int本身会报错 重载方法必须精确匹配签名,
Invoke()不会自动转换参数类型(比如传
long调用
void M(int)会失败) 被调方法抛出的异常会被包装进
TargetInvocationException,原始异常在
.InnerException里,不展开就看不到真实错误 性能极低:比直接调用慢 50–100 倍。如果需要高频调用,考虑用
Delegate.CreateDelegate()缓存委托,或用
Expression构建强类型调用器
反射不是黑魔法,它把编译期绑定推迟到运行时,代价是类型安全丢失、调试困难、性能下降。真正要用时,优先确认是否真无法用接口、泛型约束或 Source Generator 替代;一旦选了反射,务必对
null、装箱、
BindingFlags组合、异常包装这几个点保持警惕。
