C#中的反射(Reflection)机制 - 如何在运行时动态获取类型信息

来源:这里教程网 时间:2026-02-21 17:33:00 作者:

反射是C#在运行时查看、检查甚至操作类型、方法、属性、字段等元数据的能力。它不依赖编译期已知的类型,而是通过

System.Type
和相关类,在程序执行中动态发现和调用成员。关键在于“运行时”和“动态”——你不需要提前写死类名或方法名,也能加载程序集、创建实例、调用方法。

获取Type对象的几种常用方式

要使用反射,第一步是拿到

Type
实例:

typeof(MyClass)
—— 编译期已知类型,最轻量、推荐用于本程序内类型
obj.GetType()
—— 对已有实例获取其实际运行时类型(支持多态)
Type.GetType("Namespace.ClassName")
—— 通过完整字符串名称获取,需注意命名空间+程序集限定(如未指定,默认只查当前程序集)
Assembly.GetExecutingAssembly().GetType("...")
—— 显式从指定程序集中查找,适合插件或外部DLL场景

查看类型结构:成员发现与筛选

拿到

Type
后,可用一系列
GetXXX()
方法列出成员:

type.GetMethods()
返回所有公共方法;加
BindingFlags
可控制可见性(如
BindingFlags.NonPublic | BindingFlags.Instance
查私有实例方法)
type.GetProperties()
type.GetFields()
type.GetConstructors()
同理
常用组合:
BindingFlags.Public | BindingFlags.Instance
查公有实例成员;
BindingFlags.Static | BindingFlags.FlattenHierarchy
查静态继承成员
建议配合 LINQ 筛选,例如
type.GetMethods().Where(m => m.Name.StartsWith("Get"))

动态创建对象并调用成员

反射不仅看,还能做:

创建实例:
Activator.CreateInstance(type)
(调用无参构造);或传入参数数组调用带参构造
调用方法:
methodInfo.Invoke(obj, args)
,第一个参数是目标实例(静态方法传
null
读写属性:
propertyInfo.GetValue(obj)
/
propertyInfo.SetValue(obj, value)
访问字段:
fieldInfo.GetValue(obj)
/
fieldInfo.SetValue(obj, value)
(对私有字段也有效)

性能与安全注意事项

反射灵活但有代价:

比直接调用慢得多——JIT无法优化,每次都要解析元数据、校验权限、装箱拆箱。高频场景建议缓存
MethodInfo
或用
Delegate.CreateDelegate
转为委托
绕过编译检查,容易在运行时报
TargetInvocationException
ArgumentException
,务必做好 try-catch
.NET Core/.NET 5+ 默认禁用某些反射操作(如访问非公开成员),需确保运行时有对应权限(如
ReflectionPermission
已废弃,但部分策略仍影响行为)
混淆工具(如 ILLink、Dotfuscator)可能移除未显式引用的成员,导致反射失败,必要时用
[DynamicDependency]
PreserveAttribute
标记

基本上就这些。反射不是日常首选,但在序列化、ORM、DI容器、测试模拟、插件系统等场景中不可替代——理解它怎么“看”和“动”,才能用得稳、改得准、查得清。

相关推荐