大纲
- 反射是什么
- 为什么学习反射
- 反射在哪个命名空间上
- Type
- Type常用属性和方法
- 元数据是什么
- 反射与Type和元数据之间的关系是什么?
- 反射基本步骤
- BindingFlags
- 反射获取构造函数并实例对象
- 反射获取对象方法并执行
- 反射获取静态方法并执行
- 加载程序集并查看程序集中类型
1.反射概念
什么是反射?
反射(Reflection)是.NET框架提供的一种强大机制,它允许程序在运行时动态获取类型信息、创建对象、调用方法和访问属性,而无需在编译时知道这些类型的具体信息
反射,就是这个让你能"透视"并操作这个黑盒子的X光机。
为什么要学习反射
为了实现可以让开发者,通过代码,解析dll文件exe程序中的内容。为了开发方便
1. 核心命/h名空间和类
System.Reflection - 反射功能的核心命名空间
// Type - 表示类型声明(类、接口、数组等)
// Assembly - 表示程序集,可加载和操作DLL/EXE文件
2.Type入门到精通
1.什么是type?
Type 是一个包含类型信息的类。它是访问元数据(Metadata)的主要入口,是进行反射操作的"钥匙"或"手柄"。
理解:每个数据类型都可以获取到Type, 反之 type对象也包含数据类型的所有信息:例如:类型名,成员
type能做什么?
通过Type 我们可以获取什么内容呢?
- 获取类型名称
- 获取类型的全部名称
- 获取类型的成员:构造函数,字段,属性,方法,事件
- 类型继承了谁,实现了哪些接口
- 实例对象
2.获取type三种方式
class Person{}
class UserInfo
方式一:适合已经获取到具体数据类型
// 方式1:通过 typeof 运算符(编译时已知类型)
Type pType = typeof(Program);
方式二:适合已经知道类型的完成名称 并且引用到项目中
// 方式2:通过对象实例的 GetType() 方法(运行时获取)
Person person = new Person();
Type type = person.GetType();
方式三: 适合已经存在具体实例
// 方式3:通过类型名称字符串动态获取(非常常用!)
///Type.GetType("namespace.class");
///作用:根据类名,获取类的类型
///参数:完整的类型名(必须包含命名空间)
Type pType1 = Type.GetType("_01反色.Person");
方式四:通过程序获取type 适合:只知道程序集和自己需要的类型命名和类型
// 加载程序集
Assembly assembly = Assembly.LoadFrom("dll文件路径");
// 获取程序集中所有TYpe
Type[] types = assembly.GetTypes();
// 获取特定的Type
Type stuType = assembly.GetType("Tools.Student");
3. Type探索属性。字段:函数
// 获取所有Public公共的属性
var props = type.GetProperties();
foreach (PropertyInfo pi in props)
{
Console.WriteLine(pi.Name+" "+pi.PropertyType.Name);
// 输出 Name string
}
var pFields = type.GetFields();
foreach (FieldInfo fi in pFields)
{
Console.WriteLine($"字段:{fi.Name} 类型:{fi.FieldType.Name}");
// 输出 id int 包含系统自动生成
// 输出 Num int
}
var methods = type.GetMethods();
foreach (MethodInfo mi in methods)
{
Console.WriteLine(mi.Name);
// 输出:实例函数,继承函数,访问器get set
}
4.Type条件查询信息
// 获取所有公共实例成员(包括继承的)
var flags = BindingFlags.Public | BindingFlags.Instance;
// 获取所有公共和非公共实例成员(包括私有字段和继承的)
var flags1 = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
// 获取仅声明于当前类型的成员(排除继承的) + 公共实例
var flags2 = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly;
// 获取静态成员
var flags3 = BindingFlags.Public | BindingFlags.Static;
// 私有的静态
var flags4 = BindingFlags.NonPublic | BindingFlags.Static;
// 切换变量查看结果
var pFields = type.GetFields(flags);
foreach (FieldInfo fi in pFields)
{
Console.WriteLine($"字段:{fi.Name} 类型:{fi.FieldType.Name}");
}
BindingFlags
BindingFlags是什么
BindingFlags:告诉你"要找什么"和"在哪找"。
BindingFlags 是一个枚举(Enum),用于在反射调用(如 Type.GetMethods(), Type.GetProperties() 等)时,指定要搜索的成员类型、可见性、作用域等筛选条件。
详解
基础标志
|-------------------------|------------|------------|
| 枚举值 | 作用 | 说明 |
| BindingFlags.Instance | 获取实例成员 | 对象。成员(非静态) |
| BindingFlags.Static | 获取静态成员 | 类名。成员 |
注意:这两个至少选择其中一个,必须写
访问权限的表示
|--------------------------|-------------|-------------------------------|
| 枚举值 | 作用 | 说明 |
| BindingFlags.Public | 获取公共成员 | public 修饰 |
| BindingFlags.NonPublic | 获取非公共成员 | private/protected/internal 修饰 |
反射常用组合
|---------------------------------|----------------|-----------------------|
| 枚举值 | 作用 | 适用场景 |
| BindingFlags.IgnoreCase | 忽略名称大小写 | 不区分大小写查找方法 / 属性 |
| BindingFlags.FlattenHierarchy | 展开层级获取静态成员 | 拿基类的 public static 成员 |
| BindingFlags.DeclaredOnly | 只拿当前类声明的成员 | 不获取继承的成员(只看自身) |
万能组合公式
需求 BindingFlags 组合
获取公共实例成员 Instance Public
获取私有实例成员 Instance NonPublic
获取公共静态成员 Static Public
获取私有静态成员 Static NonPublic
获取当前类自己的公共实例成员(不继承) Instance Public DeclaredOnly
5.Type属性和方法总结
属性
|-------------------|----------------------|
| 属性 | 作用 |
| Name | 获取类型的短名称(不含命名空间) |
| FullName | 获取类型的完整名称(含命名空间) |
| Namespace | 获取类型所属的命名空间 |
| BaseType | 获取类型的直接父类 |
| IsClass | 判断是否是类 |
| IsInterface | 判断是否是接口 |
| IsEnum | 判断是否是枚举 |
| IsAbstract | 判断是否是抽象类型 |
| IsSealed | 判断是否是密封类 |
| IsPublic | 判断是否是公共类型 |
| IsGenericType | 判断是否是泛型类型 |
| Assembly | 获取类型所在的程序集 |
方法
- GetConstructors()
作用:获取所有公共构造函数
参数:无
返回值:ConstructorInfo[]
调用方式:type.GetConstructors() - GetConstructor(Type[] types)
作用:获取指定参数的公共构造函数
参数:Type[] types(参数类型数组)
返回值:ConstructorInfo
调用方式:type.GetConstructor(new[] { typeof(int) }) - GetMethods()
作用:获取所有公共方法(含继承)
参数:无
返回值:MethodInfo[]
调用方式:type.GetMethods() - GetMethod(string name)
作用:获取指定名称公共方法
参数:string name(方法名)
返回值:MethodInfo
调用方式:type.GetMethod("ToString") - GetMethod(string name, Type[] types)
作用:获取指定名称+参数的方法(匹配重载)
参数:string name, Type[] types
返回值:MethodInfo
调用方式:type.GetMethod("Equals", new[] { typeof(object) }) - GetProperties()
作用:获取所有公共属性
参数:无
返回值:PropertyInfo[]
调用方式:type.GetProperties() - GetProperty(string name)
作用:获取指定名称公共属性
参数:string name(属性名)
返回值:PropertyInfo
调用方式:type.GetProperty("Length") - GetFields()
作用:获取所有公共字段
参数:无
返回值:FieldInfo[]
调用方式:type.GetFields() - GetField(string name)
作用:获取指定名称公共字段
参数:string name(字段名)
返回值:FieldInfo
调用方式:type.GetField("MaxValue") - GetEvents()
作用:获取所有公共事件
参数:无
返回值:EventInfo[]
调用方式:type.GetEvents() - GetEvent(string name)
作用:获取指定名称公共事件
参数:string name(事件名)
返回值:EventInfo
调用方式:type.GetEvent("Click") - GetInterfaces()
作用:获取类型实现的所有接口
参数:无
返回值:Type[]
调用方式:type.GetInterfaces() - GetInterface(string name)
作用:获取指定名称接口
参数:string name(接口名)
返回值:Type
调用方式:type.GetInterface("IEnumerable") - GetMembers()
作用:获取所有公共成员(方法/属性/字段/事件等)
参数:无
返回值:MemberInfo[]
调用方式:type.GetMembers() - GetMember(string name)
作用:获取指定名称的所有成员
参数:string name(成员名)
返回值:MemberInfo[]
调用方式:type.GetMember("Length") - GetCustomAttributes(bool inherit)
作用:获取类型所有自定义特性
参数:bool inherit(是否继承)
返回值:object[]
调用方式:type.GetCustomAttributes(true) - GetCustomAttributes(Type attributeType, bool inherit)
作用:获取指定类型的特性
参数:Type attributeType, bool inherit
返回值:object[]
调用方式:type.GetCustomAttributes(typeof(ObsoleteAttribute), true) - GetGenericArguments()
作用:获取泛型类型参数
参数:无
返回值:Type[]
调用方式:typeof(List).GetGenericArguments() - GetGenericTypeDefinition()
作用:获取泛型类型定义(如 List<>)
参数:无
返回值:Type
调用方式:typeof(List).GetGenericTypeDefinition() - GetElementType()
作用:获取数组/指针元素类型
参数:无
返回值:Type
调用方式:typeof(int[]).GetElementType() - IsSubclassOf(Type parentType)
作用:判断是否为某类子类(不含自身)
参数:Type parentType
返回值:bool
调用方式:type.IsSubclassOf(typeof(object)) - IsAssignableFrom(Type c)
作用:判断类型是否可赋值兼容
参数:Type c
返回值:bool
调用方式:typeof(IEnumerable).IsAssignableFrom(typeof(string)) - IsInstanceOfType(object obj)
作用:判断对象是否为该类型实例
参数:object obj
返回值:bool
调用方式:type.IsInstanceOfType(obj) - Equals(Type o)
作用:判断是否为同一类型
参数:Type o
返回值:bool
调用方式:type1.Equals(type2)
3.反射应用
1. 程序集加载
准备一个程序集.dll 中有 Class MenuInfo: MenuId MenuName
// 方式1:通过程序集名称(不含后缀)
Assembly ass = Assembly.Load("Models");
// 方式2:通过文件绝对路径
Assembly ass = Assembly.LoadFile(@"D:\路径\Models.dll");
// 方式3:通过程序集文件名称(含后缀)
Assembly ass = Assembly.LoadFrom("Models.dll");
2.实例对象三种方式与动态创建
实例对象三种方式
// 获取类型的Type对象
Type type = typeof(Person);
// ------------------三种创建实例的方式
// 直接实例化
Person user1 = new Person();
// 泛型方式
Person p = Activator.CreateInstance<UserInfo>();
// 通过Type对象
Person user3 = (Person)Activator.CreateInstance(type);
动态创建,
// 1.动态创建对象
Type personType = Type.GetType("_01反色.Person");
object p = Activator.CreateInstance(personType); // 相当于 new Person()
3. 构造函数和实例对象
// 获取所有公有构造函数
var cons = type.GetConstructors();
// 获取特定构造函数
ConstructorInfo cons1 = type.GetConstructor(new Type[] { }); // 无参构造
ConstructorInfo cons2 = type.GetConstructor(new Type[] { typeof(int), typeof(string) }); // 带参构造
// 使用构造函数创建实例
UserInfo user5 = (UserInfo)cons1.Invoke(null);
object user6 = cons2.Invoke(new object[] { 12, "Mr.Sun" });
4. 方法调用
实例方法调用语法总结
MethodInfo fun = type.GetMethod("函数名");
------无参数无返回调用--------------
fun.Invoke(实例对象变量,null);
-------有参数无返回值-----------
fun.Invoke(实例对象变量,new object[] {实参1,实参2});
-------无参数有返回值----------
object res = fun.Invoke(实例对象变量,null);
---------有参数有返回值----------
object res = fun.Invoke(实例对象变量,new object[] {实参1,实参2});;
注意:有返回值的,将res 转化为指定的类型,
方法调用案例
Type type = Type.GetType("_04反射调用方法.Student");
---- 有参构造函数-----
Type[] ctorPam = new Type[] { typeof(string), typeof(int) };
ConstructorInfo ctor = type.GetConstructor(ctorPam);
// 实例对象
Student stu = ctor.Invoke(new object[] { "张三", 18 }) as Student;
----------获取指定方法Show--------------
MethodInfo show = type.GetMethod("Show");
-------- 调用方法 无参数无返回值------------
show.Invoke(stu, null);
Console.WriteLine("------------------------");
---------获取指定方法SayHello--------------
MethodInfo sayHello = type.GetMethod("SayHello");
-------调用方法 有参数无返回值------
sayHello.Invoke(stu,new object[] { "李四"});
Console.WriteLine("------------------------");
// 获取指定方法Add
MethodInfo add = type.GetMethod("Add");
-------调用方法 有参数有返回值----------
int res = (int)add.Invoke(stu,new object[] {1,2 });
Console.WriteLine(res);
Console.WriteLine("------------------------");
// 获取指定方法GetName
MethodInfo getName = type.GetMethod("GetName");
---------调用方法 无参数有返回值---------
string res1 = getName.Invoke(stu, null).ToString();
Console.WriteLine(res1);
静态方法调用语法总结
MethodInfo fun = type.GetMethod("函数名");
------无参数无返回调用--------------
fun.Invoke(null,null);
-------有参数无返回值-----------
fun.Invoke(null,new object[] {实参1,实参2});
-------无参数有返回值----------
object res = fun.Invoke(null,null);
---------有参数有返回值----------
object res = fun.Invoke(null,new object[] {实参1,实参2});;
注意:有返回值的,将res 转化为指定的类型,
静态方法调用
Type type = typeof(Student);
MethodInfo method = type.GetMethod("Show");
method.Invoke(null, null);
MethodInfo method1 = type.GetMethod("Show1");
method1.Invoke(null, new object[] { 10 });
MethodInfo method2 = type.GetMethod("Show2");
int res = (int)method2.Invoke(null, new object[] { 10 });
Console.WriteLine(res);
class Student
{
public static void Show() { Console.WriteLine("静态方法"); }
public static void Show1(int a) { Console.WriteLine("a=" + a); }
public static int Show2(int a) { return a; }
}
9. 实例属性的操作
-
根据属性名获取属性对象
-
给某个对象的属性赋值
-
查看某个对象属性赋值
// 获取Age属性
PropertyInfo proAge = type.GetProperty("Age");
// stu.Age = 18
proAge.SetValue(stu, 18);
// stu.Age
Console.WriteLine(proAge.GetValue(stu));
10.总结反射步骤
- 加载程序集
- 获取指定Type
- 通过Type探索元数据的结构
- 实例对象
- 操作实例对象属性
- 调用方法
4.元数据
元数据(Metadata)总结: 就是关于数据的数据。它本身不是核心内容,但它描述了核心内容的特征、属性、来源、关系等信息
反射与Type和元数据之间的关系是什么?
1:Type是反射的基石,是反射的钥匙
2:Type是通过元数据,才能获取类型中信息:类型名,有哪些成员
3:通过Type解析元数据的过程就是i反射,反射Reflection 中有 描述成员的具体实例类型。例如:
- ContructorInfo 构造函数
- PropertyInfo 属性
- FildInfo 字段
- MethodInfo 方法