C#反射
C# 反射使用指南
1. 反射概念
- 元数据(Metadata):程序及类型的相关信息,如类、方法、字段、属性等,存储在程序集(.dll 或 .exe)中。
- 反射(Reflection):程序在运行时获取自身或其他程序集的元数据,并可动态实例化对象、访问成员、调用方法。
- 程序集(Assembly):.NET 的代码打包单位,分为 DLL(库)和 EXE(可执行文件)。
2. 获取类型信息(Type)
2.1 获取 Type 的三种方式
int a = 1;
// 1. 对象实例的 GetType()
Type t1 = a.GetType();
// 2. typeof 关键字
Type t2 = typeof(int);
// 3. Type.GetType(string) 通过字符串获取
Type t3 = Type.GetType("System.Int32")!;
注意:
Type.GetType(string)默认只在当前程序集和系统程序集搜索类型,跨程序集可能返回 null。
2.2 Type 常用属性
Type t = typeof(Test);
Console.WriteLine(t.Assembly); // 获取类型所属程序集
Console.WriteLine(t.Namespace); // 获取命名空间
Console.WriteLine(t.Name); // 获取类名
3. 获取类成员
3.1 获取公共成员
Type t = typeof(Test);
MemberInfo[] members = t.GetMembers(); // 获取所有公共成员
foreach (var m in members)
Console.WriteLine(m);
⚡ 默认只获取 公共实例成员,无需额外指定
BindingFlags。
3.2 获取字段(FieldInfo)
// 获取公共或非公共实例字段,需要指定 BindingFlags
FieldInfo field = t.GetField("name", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
// 设置字段值(实例字段)
field.SetValue(obj, "Alice");
// 获取字段值(实例字段)
Console.WriteLine(field.GetValue(obj));
// 静态字段
FieldInfo staticField = t.GetField("StaticValue", BindingFlags.Static | BindingFlags.Public);
staticField.SetValue(null, 100);
Console.WriteLine(staticField.GetValue(null));
⚡ GetValue/SetValue 参数规则:
- 实例字段:传入对象实例
- 静态字段:传入
null
3.3 获取方法(MethodInfo)
// 公共实例方法(可省略 BindingFlags)
MethodInfo method = t.GetMethod("Add", new Type[]{ typeof(int) });
method.Invoke(obj, new object[]{ 10 }); // 调用实例方法
// 静态方法必须指定 Static 或直接传 null
MethodInfo staticMethod = t.GetMethod("StaticAdd", BindingFlags.Static | BindingFlags.Public);
staticMethod.Invoke(null, new object[]{ 5 });
3.4 获取构造函数(ConstructorInfo)
// 公共无参构造
ConstructorInfo ctor = t.GetConstructor(Type.EmptyTypes);
object obj = ctor.Invoke(null);
// 私有无参构造
ConstructorInfo privateCtor = t.GetConstructor(
BindingFlags.Instance | BindingFlags.NonPublic,
null,
Type.EmptyTypes,
null
);
object obj2 = privateCtor.Invoke(null);
// 使用 Activator
object obj3 = Activator.CreateInstance(t, true); // true:允许反射私有构造函数
⚡ 建议:尽量使用
Activator.CreateInstance,支持私有构造函数,代码简洁。
4. BindingFlags 使用注意
- 默认只能找到 公共实例成员
- 必须指定 Instance 或 Static 才能获取非默认成员
- 常用组合:
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static
| Flag | 作用 |
|---|---|
| Public | 查找公共成员 |
| NonPublic | 查找非公共成员(private/protected) |
| Instance | 查找实例成员 |
| Static | 查找静态成员 |
4.1 省略 BindingFlags 的场景
| 场景 | 是否可省略 BindingFlags | 说明 |
|---|---|---|
| 公共实例成员 | ✅ 可省略 | 默认返回公共实例成员,如 GetMethod("Add") |
| 公共静态成员 | ❌ 不可省略 | 必须加 Static |
| 非公共成员(私有/保护) | ❌ 不可省略 | 必须加 NonPublic + Instance/Static |
| GetProperties / GetFields 默认 | ✅ 返回公共实例成员 | 若要获取私有或静态字段,需要明确指定 BindingFlags |
⚡ 结论:公共实例成员可省略 BindingFlags,其余情况必须指定
5. 动态实例化对象(Activator)
Type t = typeof(T);
// 无参构造
T obj1 = (T)Activator.CreateInstance(t);
// 有参构造
T obj2 = (T)Activator.CreateInstance(t, 99, "Hello");
// 支持私有构造函数
T obj3 = (T)Activator.CreateInstance(t, true);
//语法糖 仅支持无参构造 没有重载
T obj1 = Activator.CreateInstance<T>()
⚡ Activator.CreateInstance 优势:
- 简化 ConstructorInfo 调用
- 支持私有构造函数
- 可直接传入构造函数参数
6. 跨程序集反射
6.1 问题
Type t = Type.GetType("BNameSpace.ClassName"); // 返回 null
- 原因:
Type.GetType(string)默认只在 当前程序集 或系统程序集查找,找不到外部 DLL 的类型。
6.2 解决方案
// 1. 先加载目标程序集
Assembly asm = Assembly.LoadFrom("B.dll");
// 2. 从程序集获取类型
Type t = asm.GetType("BNameSpace.ClassName");
// 3. 调用构造函数、方法等
object obj = Activator.CreateInstance(t, 1, "abc")!;
MethodInfo method = t.GetMethod("DoSomething")!;
method.Invoke(obj, new object[]{ 10 });
6.3 使用 typeof 的跨程序集方式
typeof(B.Class)编译时会检查类型存在,需要添加对 B.dll 的引用- 编译通过 → 运行时安全可靠
7. 总结反射使用规范
-
优先使用
typeof或对象实例的GetType(),安全可靠。 -
跨程序集反射,优先使用
Assembly.Load或Assembly.LoadFrom+Assembly.GetType。 -
访问非公共成员,必须指定
BindingFlags.NonPublic和 Instance/Static。 -
动态实例化对象推荐使用
Activator.CreateInstance,支持私有构造函数。 -
慎用
Type.GetType(string),容易返回 null,适合反射系统程序集类型。 -
公共实例成员可以省略 BindingFlags,静态或私有成员必须指定。
-
FieldInfo.GetValue/SetValue:
- 实例字段 → 传对象实例
- 静态字段 → 传
null
-
PropertyInfo.GetValue/SetValue 遵循属性 getter/setter,静态属性第一个参数传
null。
8. 推荐反射操作流程
获取类型
Type t = typeof(MyClass); // 或 Assembly.GetType("Namespace.ClassName")
获取成员
// 公共或非公共实例字段
FieldInfo f = t.GetField("name", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
// 公共实例方法
MethodInfo m = t.GetMethod("Add", new Type[]{ typeof(int) });
// 构造函数
ConstructorInfo ctor = t.GetConstructor(Type.EmptyTypes);
创建对象
object obj = ctor.Invoke(null);
调用方法 / 访问字段
// 调用方法
m.Invoke(obj, new object[]{ 10 });
// 访问字段
f.SetValue(obj, "Alice");
⚡ 补充:
- 静态字段或方法 → GetValue/SetValue / Invoke 第一个参数传
null- 公共实例成员 → 可省略 BindingFlags

浙公网安备 33010602011771号