C#知识:反射初探
1、反射相关概念
- 程序集:编译器将源代码编译后产生的可执行的文件(.dll或.exe),一个程序集一般包含多个类
- 元数据:描述数据特征的数据,例如类的元数据描述了这个类的类名、包含哪些成员等信息
- 反射:程序在运行过程中能够查看自身或其他程序的元数据的行为
- 反射作用:能够在程序运行过程中,利用类的元数据来实例化对象以及操作对象
2、 Type类(类的信息类):获取指定类的元数据
2.1 获取Type:
- Object类中的GetType()方法
这种方法需要有类的对象,但一般没有这个对象
int a = 10;
Type type1 = a.GetType();
Console.WriteLine(type1);
- 通过类名+typeof方法
这种方法需要类名,而且这个类能够访问到
Type type2 = typeof(int);
Console.WriteLine(type2);
- 通过类名+Type.GetType()获取,类名包含名称空间
Type type3 = Type.GetType("System.Int32");
Console.WriteLine(type3);
输出

2.2 获取程序集信息
Console.WriteLine(type1.Assembly);
Console.WriteLine(type2.Assembly);
Console.WriteLine(type3.Assembly);
输出

2.3 利用反射创建和使用对象
2.3.1 获取类中所有的公共成员
Type myType = Type.GetType("LearnReflection.Student");
MemberInfo[] infos = myType.GetMembers();
for(int i = 0; i < infos.Length; i++)
{
Console.WriteLine(infos[i]);
}
class Student
{
public string name;
public int Age { get; private set; }
private int score;
public Student(string nmae, int age, int score) : this(nmae, age)
{
this.score = score;
}
public Student(string name, int age)
{
this.name = name;
Age = age;
}
public Student() { }
public void PrintInfo()
{
Console.WriteLine($"Name: {name}");
Console.WriteLine($"Age: {Age}");
PrintScore();
}
private void PrintScore()
{
Console.WriteLine($"Score:{score}");
}
}
- 输出包括Objec类中非静态公共方法、公共成员变量、公共成员方法、构造函数、公共属性中的公共方法、公共属性
- 因为子类继承Object类不会继承它的静态方法

2.3.2 获取类的公共构造函数并调用
获取类的所有公共构造函数
ConstructorInfo[] ctors = myType.GetConstructors();
for(int i = 0;i < ctors.Length; i++)
{
Console.WriteLine(ctors[i]);
}
输出

获得指定构造函数,需要传入一个类型数组与构造函数参数列表进行匹配
获取无参构造并执行
ConstructorInfo ctor1 = myType.GetConstructor(new Type[0]);
Student student1 = ctor1.Invoke(null) as Student;
Console.WriteLine(student1.Age); //0
输出

获取有参构造并执行
ConstructorInfo ctor2 = myType.GetConstructor(new Type[] { typeof(string), typeof(int), typeof(int)});
Student student2 = ctor2.Invoke(new object[] { "张飞", 18, 100 }) as Student;
Console.WriteLine(student2.name);
输出

2.3.3 获取类的公共成员变量
获取所有公共成员变量
FieldInfo[] fieldInfos = myType.GetFields();
for(int i = 0;i<fieldInfos.Length;i++)
{
Console.WriteLine(fieldInfos[i]);
}
输出

获取指定名称的公共成员变量
FieldInfo fieldInfo = myType.GetField("name");
Console.WriteLine(fieldInfo);
输出

2.3.4 通过反射获取和设置对象的值
通过反射获取对象的值
Student student3 = new Student("关羽",20,600);
Console.WriteLine(fieldInfo.GetValue(student3));
输出

通过反射获取和设置对象的值
fieldInfo.SetValue(student3, "刘备");
Console.WriteLine(fieldInfo.GetValue(student3));
输出

2.3.5 通过反射获取类的公共成员方法
获取所有公共成员方法
MethodInfo[] methodInfos = myType.GetMethods();
for(int i = 0; i < methodInfos.Length; i++)
{
Console.WriteLine(methodInfos[i]);
}
输出:不包含私有方法和protected方法

通过反射获取并执行指定名称的方法
MethodInfo methodInfo = myType.GetMethod("PrintInfo");
methodInfo.Invoke(student3, new object[0]);
输出

3、反射关键类Activator
- 用于快速实例化对象
无参构造
Student student4 = Activator.CreateInstance(typeof(Student)) as Student;
有参构造
Student student5 = Activator.CreateInstance(typeof(Student), "曹操", 25, 1000) as Student;
student5.PrintInfo();
输出

4、反射关键类Assembly
- 用来加载程序集
三种加载程序集的方式
4.1 加载同一文件夹下的其他程序集
Assembly assembly = Assembly.Load("程序集名称");
4.2 加载不同文件夹下的其他程序集
4.2.1 LoadFile
- 加载到"无上下文"(LoadNeither)
- 程序集被独立加载,与其他上下文隔离
Assembly assembly2 = Assembly.LoadFile("目标程序集的完全限定路径");
4.2.2 LoadFrom
- 使用特殊的"LoadFrom"上下文
- 程序集可以被其他需要相同程序集的代码共享
Assembly assembly3 = Assembly.LoadFrom("目标程序集的完全限定路径");
4.3 加载程序集示例
新建类库

编写自定义类
namespace TestReflecttionClassLib
{
public class Point
{
public int x;
public int y;
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
}
}
右键项目,编译生成.dll程序集

加载程序集,获取和使用Type对象
Assembly assembly = Assembly.LoadFrom(@"E:\ViusualStudio2022_Workplace\解决方案_练习\TestReflecttionClassLib\bin\Debug\net8.0\TestReflecttionClassLib.dll");
Type[] types = assembly.GetTypes();
for(int i = 0; i<types.Length; i++)
{
Console.Write(types[i]);
}
//通过名称获取指定类的元信息
Type type = assembly.GetType("TestReflecttionClassLib.Point");
MemberInfo[] memberInfos = type.GetMembers();
for(int i = 0;i<memberInfos.Length; i++)
{
Console.WriteLine(memberInfos[i]);
}
输出

5、完整代码示例:
源文件1
using System.Reflection;
namespace LearnReflection
{
class Student
{
public string name;
public int Age { get; private set; }
private int score;
public Student(string nmae, int age, int score) : this(nmae, age)
{
this.score = score;
}
public Student(string name, int age)
{
this.name = name;
Age = age;
}
public Student() { }
public void PrintInfo()
{
Console.WriteLine($"Name: {name}");
Console.WriteLine($"Age: {Age}");
PrintScore();
}
private void PrintScore()
{
Console.WriteLine($"Score:{score}");
}
}
internal class Program
{
static void Main(string[] args)
{
//Type类(类的信息类):获取指定类的元数据
//获取Type
//1.Object类中的GetType()方法
int a = 10;
Type type1 = a.GetType();
Console.WriteLine(type1);
//2.通过类名+typeof方法
//这种方法需要类名,而且这个类能够访问到
Type type2 = typeof(int);
Console.WriteLine(type2);
//3.通过类名+Type.GetType()获取,类名包含名称空间
Type type3 = Type.GetType("System.Int32");
Console.WriteLine(type3);
//获取程序集信息
Console.WriteLine(type1.Assembly);
Console.WriteLine(type2.Assembly);
Console.WriteLine(type3.Assembly);
//利用反射创建和使用对象
//获取类中所有的公共成员
Type myType = Type.GetType("LearnReflection.Student");
MemberInfo[] infos = myType.GetMembers();
for(int i = 0; i < infos.Length; i++)
{
Console.WriteLine(infos[i]);
}
//包括Objec类中非静态公共方法、公共成员变量、公共成员方法、构造函数、公共属性中的公共方法
//因为子类继承Object类不会继承它的静态方法
//获取类的公共构造函数并调用
ConstructorInfo[] ctors = myType.GetConstructors();
for(int i = 0;i < ctors.Length; i++)
{
Console.WriteLine(ctors[i]);
}
//获得指定构造函数,需要传入一个类型数组与构造函数参数列表进行匹配
//获取无参构造并执行
ConstructorInfo ctor1 = myType.GetConstructor(new Type[0]);
Student student1 = ctor1.Invoke(null) as Student;
Console.WriteLine(student1.Age); //0
//获取有参构造并执行
ConstructorInfo ctor2 = myType.GetConstructor(new Type[] { typeof(string), typeof(int), typeof(int)});
Student student2 = ctor2.Invoke(new object[] { "张飞", 18, 100 }) as Student;
Console.WriteLine(student2.name);
//获取类的公共成员变量
//获取所有公共成员变量
FieldInfo[] fieldInfos = myType.GetFields();
for(int i = 0;i<fieldInfos.Length;i++)
{
Console.WriteLine(fieldInfos[i]);
}
//获取指定名称的公共成员变量
FieldInfo fieldInfo = myType.GetField("name");
Console.WriteLine(fieldInfo);
//通过反射获取和设置对象的值
Student student3 = new Student("关羽",20,600);
//获取
Console.WriteLine(fieldInfo.GetValue(student3));
//设置
fieldInfo.SetValue(student3, "刘备");
Console.WriteLine(fieldInfo.GetValue(student3));
//通过反射获取类的公共成员方法
MethodInfo[] methodInfos = myType.GetMethods();
for(int i = 0; i < methodInfos.Length; i++)
{
Console.WriteLine(methodInfos[i]);
}
//通过反射获取指定名称的方法
MethodInfo methodInfo = myType.GetMethod("PrintInfo");
//执行方法
methodInfo.Invoke(student3, new object[0]);
//反射关键类Activator
Student student4 = Activator.CreateInstance(typeof(Student)) as Student;
//有参构造
Student student5 = Activator.CreateInstance(typeof(Student), "曹操", 25, 1000) as Student;
student5.PrintInfo();
//反射关键类Assembl
Assembly assembly = Assembly.LoadFrom(@"E:\ViusualStudio2022_Workplace\解决方案_练习\TestReflecttionClassLib\bin\Debug\net8.0\TestReflecttionClassLib.dll");
Type[] types = assembly.GetTypes();
for(int i = 0; i<types.Length; i++)
{
Console.Write(types[i]);
}
//通过名称获取指定类的元信息
Type type = assembly.GetType("TestReflecttionClassLib.Point");
MemberInfo[] memberInfos = type.GetMembers();
for(int i = 0;i<memberInfos.Length; i++)
{
Console.WriteLine(memberInfos[i]);
}
}
}
}
源文件2
namespace TestReflecttionClassLib
{
public class Point
{
public int x;
public int y;
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
}
}
6、参考资料
- 《唐老狮C#》
本文结束,感谢您的阅读~

2201

被折叠的 条评论
为什么被折叠?



