C#反射

C# 反射使用指南

1. 反射概念

  • 元数据(Metadata):程序及类型的相关信息,如类、字段、属性、方法、构造函数等,存储在程序集(.dll 或 .exe)中。
  • 反射(Reflection):程序在运行时获取自身或其他程序集的元数据,并可动态实例化对象、访问成员、调用方法。
  • 程序集(Assembly):.NET 的代码打包单位,分为 DLL(库)和 EXE(可执行文件)。

2. 获取类型信息(Type)

2.1 获取 Type 的三种方式

// 1. typeof 关键字(最常用)
Type t = typeof(MyClass);

// 2. Type.GetType(string) 
Type t = Type.GetType("MyClass");

// 3. 对象实例的 GetType()(不常用 因为我们要反射的自定义类一般拿不到对象 系统类又没必要反射)
MyClass a = new MyClass();
Type t = a.GetType();

//当加载其它程序集类时
// typeof 参数补上命名空间 要使用using获取程序集空间(这也意味着不能动态加载 如果场景中没有该程序集空间的脚本就会报错)
Type t = typeof(OtherNamespace.OtherClass);
// Type.GetType 默认只在当前程序集和系统程序集搜索类型,跨程序集可能返回 null,要先反射其它程序集,通过其它程序集的GetType方法获取类型信息
Assembly assembly = Assembly.LoadFrom(@"C:\唐老狮Unity\C#进阶\Lesson16_练习题\bin\Debug\net8.0\Lesson16_练习题.dll");
Type t = assembly.GetType("OtherNamespace.OtherClass")

2.2 Type 常用属性

Type t = typeof(Test);
Console.WriteLine(t.Assembly);  // 获取类型所属程序集
Console.WriteLine(t.Namespace); // 获取命名空间
Console.WriteLine(t.Name);      // 获取类名

3. 获取类成员

3.1 获取类成员的方法

要获取什么 方法名
字段、属性、方法、构造函数 GetMembers
字段 Field GetField
属性 Property GetProperty
方法 Method GetMethod
构造函数 Constructor GetConstructor

3.2 获取类成员的方法参数

获取类成员的方法都有四个参数 (BindingFlags bindingAttr, Binder binder, Type[] types, ParameterModifier[] modifiers)

参数 说明
BindingFlags (重要) BindingFlags,指定查找规则(实例/静态、公有/非公有)
Binder (默认为null) 可选绑定器,默认传 null 就够用,控制重载匹配
Type[](重要) 构造函数参数类型数组,用于精确匹配哪一个构造函数
ParameterModifier[](默认为null) 参数修饰符,一般为 null

BindingFlags 常用字段

Flag 作用
BindingFlags.Public 查找公共成员(public)
BindingFlags.NonPublic 查找非公共成员(private/protected)
BindingFlags.Instance 查找实例成员(非static)
BindingFlags.Static 查找静态成员(static)

省略BindingFlags, Binder, Type[], ParameterModifier[]时返回的类成员的类型

获取的类成员 默认返回成员类型
MemberInfo[] members = typeof(MyClass).GetMembers()(特殊情况) 返回所有公共成员(字段/属性/方法/构造函数),包括静态
MemberInfo[] members = typeof(MyClass).GetMembers("memberName") 返回符合memberName的公共实例成员(字段/属性/方法/构造函数),不包括静态
FieldInfo field= typeof(MyClass).GetField("fieldName") 返回符合fieldName公共实例字段,不包括静态
MethodInfo methodInfo = typeof(MyClass).GetMethod("MethodName") 返回符合MethodName公共实例方法,不包括静态
ConstructorInfo constructorInfo = typeof(MyClass).GetConstructor(Type.EmptyTypes) 返回公共无参构造函数,不包括静态

types 的使用

参数个数 Type[] 数组写法
无参数 Type.EmptyTypes
一个参数 new Type[] { typeof(int) }
两个参数 new Type[] { typeof(int), typeof(string) }

3.3 获取成员

//Members 成员(字段、属性、方法、构造函数)
//获取公共成员(包含静态)
Type t = typeof(Test);
MemberInfo[] members = t.GetMembers();  

//FieldInfo 字段(常用)
//获取公共实例字段
FieldInfo field = t.GetField("Value");
field.SetValue(obj, 10);
field.GetValue(obj);
// 获取公共静态字段 
FieldInfo staticField = t.GetField("StaticValue", BindingFlags.Static | BindingFlags.Public);
//注意:静态字段不存在对象 因此使用null
staticField.SetValue(null, 10);
staticField.GetValue(null);

//PropertyInfo 属性(不常用)
//获取公共实例属性
PropertyInfo property = t.GetProperty("Value")
property.SetValue(obj, 10);
property.GetValue(obj);
//获取公共静态属性
PropertyInfo staticProperty = t.GetProperty("StaticValue", BindingFlags.Static | BindingFlags.Public);
staticProperty.SetValue(null, 10);
staticProperty.GetValue(null);

//MethodInfo 方法(常用)
// 获取公共实例方法
MethodInfo method = t.GetMethod("Add", new Type[]{ typeof(int) });
// 反射获取的方法必须使用Invoke调用
method.Invoke(obj, new object[]{ 10 });  
// 获取公共静态方法
MethodInfo staticMethod = t.GetMethod("StaticAdd", BindingFlags.Static | BindingFlags.Public);
staticMethod.Invoke(null, new object[]{ 5 });  //调用静态方法

//ConstructorInfo 构造函数(不常用 直接使用Activator.CreateInstance创建实例更方便)
// 获取公共实例构造函数
ConstructorInfo ctor = t.GetConstructor(Type.EmptyTypes);
// 反射获取的构造函数必须使用Invoke调用
object obj = ctor.Invoke(null);
// 获取私有实例无参构造函数
ConstructorInfo pctor= t.GetConstructor(
    BindingFlags.Instance | BindingFlags.NonPublic,
    null,
    Type.EmptyTypes,
    null
);
object obj2 = pctor.Invoke(null);

4. 动态实例化对象(Activator)

Type t = typeof(T);

// 无参构造
T obj1 = (T)Activator.CreateInstance(t);

// 有参构造
T obj2 = (T)Activator.CreateInstance(t, 99, "Hello");

// 支持私有构造函数(同时存在公共(public)和私有(private)无参构造函数 时,还是优先调用公共无参构造函数)
T obj3 = (T)Activator.CreateInstance(t, true);

//语法糖 仅支持无参构造 没有重载
T obj1 = Activator.CreateInstance<T>();

6. 程序集反射(不常用)

  • 如果想要使用不是自己程序集中的信息 需要先加载其它程序集 才能用Type来使用其它程序集中的信息
//三种加载程序集的函数
//方法一 一般用来加载在同一文件下的其它程序集
//Assembly assembly2 = Assembly.Load("程序集名称");

//方法二 一般用来加载不在同一文件下的其它程序集(一般使用这个)
//Assembly assembly = Assembly.LoadFrom("包含程序集清单的文件的名称或路径");

//方法三 一般用来加载不在同一文件下的其它程序集
//Assembly assembly3 =Assembly.LoadFile("要加载的文件的完全限定路径");

//1.先加载一个指定程序集
Assembly assembly = Assembly.LoadFrom(@"C:\唐老狮Unity\C#进阶\Lesson16_练习题\bin\Debug\net8.0\Lesson16_练习题.dll");
//2.再加载程序集中的一个类对象 之后才能使用反射
Type item = assembly.GetType("Lesson16_练习题.Item");
MemberInfo[] members = item.GetMembers();
for(int i = 0; i < members.Length; i++)
{
    Console.WriteLine(members[i]);
}
//通过反射实例化一个item对象
object itemObj = Activator.CreateInstance(item, 1,"123123", 2);
//得到对象中的方法 通过反射
ConstructorInfo constructoritem = item.GetConstructor(new Type[] { typeof(int), typeof(string), typeof(int) });

7. 常用反射操作流程

// 获取类型
Type t = typeof(MyClass); // 或 Assembly.GetType("Namespace.ClassName")
// 获取公共实例字段
FieldInfo field = t.GetField("name");
// 获取公共实例方法
MethodInfo method = t.GetMethod("Add", new Type[]{ typeof(int) });
// 创建对象
object obj = t.Activator.CreateInstance(t);
// 调用方法
method.Invoke(obj, new object[]{ 10 });
// 访问字段
field.SetValue(obj, "Alice");
field.GetValue(obj);
posted @ 2025-11-23 11:27  高山仰止666  阅读(2)  评论(0)    收藏  举报