添加Lesson20
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,321 @@
|
||||
using System.Reflection;
|
||||
|
||||
namespace Lesson20_反射
|
||||
{
|
||||
#region 知识回顾
|
||||
//编译器是一种翻译程序
|
||||
//它用于将源语言程序翻译为目标语言程序
|
||||
|
||||
//源语言程序:某种程序设计语言写成的,比如C#、Java、Python等
|
||||
//目标语言程序:计算机能够直接执行的机器语言程序(伪代码)
|
||||
#endregion
|
||||
|
||||
#region 知识点一 什么是程序集
|
||||
//程序集是我们写的一个代码集合,我们现在写的所有代码
|
||||
//最终都会背编译成一个程序集文件供别人使用
|
||||
//程序集文件的扩展名有两种:.exe和.dll
|
||||
//.exe:可执行程序文件,双击即可运行
|
||||
//.dll:类库文件,不能直接运行,需要被其他程序调用才能运行
|
||||
#endregion
|
||||
|
||||
#region 知识点二 元数据
|
||||
//元数据就是用来描述数据的数据
|
||||
//这个概念不仅仅用于程序上,在别的领域也有元数据
|
||||
|
||||
//说人话:
|
||||
//程序中的类,类中的函数、变量等等信息就是 程序的 元数据
|
||||
//有关程序以及类型的数据被称为 元数据,他们保存在程序集文件中
|
||||
#endregion
|
||||
|
||||
#region 知识点三 反射的概念
|
||||
//程序在运行时,可以查看其他程序集或者自身的元数据
|
||||
//一个运行的程序查看本身或者其他程序集的元数据的过程 就叫做 反射
|
||||
|
||||
//说人话:
|
||||
//在程序运行时,通过反射可以得到其他程序集或者自己程序集代码的各种信息
|
||||
//类,函数,变量,对象等等,实例化他们,执行他们,操作他们
|
||||
#endregion
|
||||
|
||||
#region 知识点四 反射的作用
|
||||
//因为反射可以在程序变异后获得信息,所以他提高了程序的拓展性和灵活性
|
||||
//1.程序运行时得到所有元数据,包括元数据的特性
|
||||
//2.程序运行时,实例化对象,操作对象
|
||||
//3.程序运行时创建新对象,用这些对象执执行任务
|
||||
#endregion
|
||||
|
||||
|
||||
class Test
|
||||
{
|
||||
private int i = 1;
|
||||
public int j = 2;
|
||||
public string str = "123";
|
||||
|
||||
public Test()
|
||||
{
|
||||
|
||||
}
|
||||
public Test(int i)
|
||||
{
|
||||
this.i = i;
|
||||
|
||||
}
|
||||
public Test(int i ,string str)
|
||||
{
|
||||
this.i = i;
|
||||
this.str = str;
|
||||
}
|
||||
}
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
|
||||
#region 知识点五 语法相关
|
||||
|
||||
#region Type类
|
||||
//Type(类的信息类)
|
||||
//他是反射功能的基础!
|
||||
//他是访问元数据的主要方式
|
||||
//使用Type的成员获取有关类型的声明信息
|
||||
//有关类型的成员(如构造函数、方法、属性、字段、事件等)
|
||||
|
||||
#region 获取Type对象的方式
|
||||
//1.万物之父 Object类的GetType()方法
|
||||
int a = 42;
|
||||
Type type = a.GetType();//得到int类型的类的信息
|
||||
Console.WriteLine(type);//获取int命名空间的全名 System.Int32
|
||||
//2.通过typeof关键字获取
|
||||
Type type2 = typeof(string);//得到string类型的类的信息
|
||||
Console.WriteLine(type2);//获取string命名空间的全名 System.String
|
||||
//3.通过类的名字 也可以获取类型
|
||||
// 注意 类名必须包含命名空间 不然找不到
|
||||
Type type3 = Type.GetType("Int32");//非全名
|
||||
Console.WriteLine(type3);//获取不到 输出空行
|
||||
type3 = Type.GetType("System.Int32");//全名
|
||||
Console.WriteLine(type3);//获取int命名空间的全名 System.Int32
|
||||
Console.WriteLine("__________________________");
|
||||
#endregion
|
||||
|
||||
#region 得到类的程序集信息
|
||||
//可以通过Type得到类型所在的程序集信息
|
||||
Console.WriteLine(type.Assembly);
|
||||
Console.WriteLine(type2.Assembly);
|
||||
Console.WriteLine(type3.Assembly);
|
||||
Console.WriteLine("__________________________");
|
||||
#endregion
|
||||
|
||||
#region 获取类中的所有公共成员
|
||||
//首先得到Type
|
||||
Type t = typeof(Test);
|
||||
//然后得到所有公共成员
|
||||
//需要引用命名空间 using System.Reflection;
|
||||
MemberInfo[] infos = t.GetMembers();
|
||||
for (int i = 0; i < infos.Length; i++)
|
||||
{
|
||||
Console.WriteLine(infos[i]);
|
||||
}
|
||||
Console.WriteLine("__________________________");
|
||||
#endregion
|
||||
|
||||
#region 获取类的公共构造函数并调用
|
||||
//1.获取所有构造函数
|
||||
ConstructorInfo[] ctors = t.GetConstructors();
|
||||
for (int i = 0; i < ctors.Length; i++)
|
||||
{
|
||||
Console.WriteLine(ctors[i]);
|
||||
}
|
||||
Console.WriteLine("__________________________");
|
||||
|
||||
|
||||
|
||||
//2.获取其中一个构造函数并执行
|
||||
//得到构造函数传入 Type数组 数组中内容按顺序时参数类型
|
||||
//执行构造函数传入 Object数组 表示按顺序传入的参数值
|
||||
|
||||
// 2-1得到无参构造并执行
|
||||
ConstructorInfo info = t.GetConstructor(new Type[0]);//由于使用时必须要传入参数类型数组 所以无参时传入空数组
|
||||
//执行无参构造方法
|
||||
//info.Invoke(null);//因为是无参构造函数,所以传入参数为null
|
||||
//甚至可以实例化
|
||||
Test obj = info.Invoke(null) as Test;
|
||||
Console.WriteLine(obj.j);
|
||||
Console.WriteLine("__________________________");
|
||||
// 2-2得到无参构造并执行
|
||||
ConstructorInfo info2 = t.GetConstructor(new Type[] { typeof(int)});
|
||||
//执行有参构造方法
|
||||
Test obj2 = info2.Invoke(new object[] { 10 }) as Test;
|
||||
//Console.WriteLine(obj2.i);//i是private类型所以外部无法访问
|
||||
//执行两个参数的构造函数
|
||||
ConstructorInfo info3 = t.GetConstructor(new Type[] { typeof(int), typeof(string) });
|
||||
Test obj3 = info3.Invoke(new object[] { 6 , "123" }) as Test;
|
||||
Console.WriteLine(obj.str);
|
||||
Console.WriteLine("__________________________");
|
||||
#endregion
|
||||
|
||||
#region 获取类的公共成员变量
|
||||
//1.得到所有成员变量名和类型
|
||||
FieldInfo[] fieldInfos = t.GetFields();
|
||||
for (int i = 0; i < fieldInfos.Length; i++)
|
||||
{
|
||||
Console.WriteLine(fieldInfos[i]);
|
||||
}
|
||||
Console.WriteLine("__________________________");
|
||||
//2.得到指定成员变量名和类型
|
||||
FieldInfo infoJ = t.GetField("j");
|
||||
Console.WriteLine(infoJ);
|
||||
Console.WriteLine("__________________________");
|
||||
//3.通过反射获取和设置成员变量的值
|
||||
Test test = new Test();
|
||||
test.j = 99;
|
||||
test.str = "2222";
|
||||
//3-1获取成员变量j的值
|
||||
Console.WriteLine(infoJ.GetValue(test));//注意这里需要传入对象,因为都是写在一个文档里所以直接写上面new的test了
|
||||
//如果是其他程序集中则需要先通过反射实例化对象再传入
|
||||
//3-2设置成员变量j的值
|
||||
infoJ.SetValue(test, 100);
|
||||
Console.WriteLine(infoJ.GetValue(test));
|
||||
Console.WriteLine("__________________________");
|
||||
#endregion
|
||||
|
||||
#region 获取类的公共成员方法
|
||||
//通过Type类中的 GetMethods()方法可以获取类的所有公共方法
|
||||
//MethodInfo是方法的反射信息类
|
||||
Type strType = typeof(string);
|
||||
//1.如果存在方法重载 用Type数组表示参数类型
|
||||
MethodInfo[] methods = strType.GetMethods();
|
||||
for (int i = 0; i < methods.Length; i++)
|
||||
{
|
||||
Console.WriteLine(methods[i]);
|
||||
}
|
||||
Console.WriteLine("__________________________");
|
||||
//2.调用该方法
|
||||
//注意:如果是静态方法 则传入null 如果是实例方法 则传入对象
|
||||
MethodInfo subStr = strType.GetMethod("Substring",new Type[] { typeof(int),typeof(int)});
|
||||
string str = "hello world!";
|
||||
object result = subStr.Invoke(str, new Object[] { 7, 5 });
|
||||
Console.WriteLine(result);
|
||||
Console.WriteLine("__________________________");
|
||||
#endregion
|
||||
|
||||
#region 其他
|
||||
//Type;
|
||||
//得枚举
|
||||
//GetEnumName();
|
||||
//GetEnumNames();
|
||||
|
||||
//得事件
|
||||
//GetEvent();
|
||||
//GetEvents();
|
||||
|
||||
//得接口
|
||||
//GetInterface();
|
||||
//GetInterfaces();
|
||||
|
||||
//得属性
|
||||
//GetProperty();
|
||||
//GetPropertys();
|
||||
|
||||
//还有很多其他方法 可以查看文档学习
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region Assembly类
|
||||
//程序集类
|
||||
//主要用来加载其他程序集,加载后
|
||||
//才能用Type来使用其他程序集中的信息
|
||||
//如果想要使用不是自己程序集中的内容 需要先加载程序集
|
||||
//比如dll文件(库文件)
|
||||
//简单的把库文件看成一种代码仓库,它提供给使用者一些可以直接拿来用的变量、函数、类等等
|
||||
|
||||
//三种加载程序集的函数
|
||||
//一般用来加载在同一文件下的其他程序集
|
||||
//Assembly asembly2= Assembly.Load("程序集名称");
|
||||
|
||||
//一般用来加载不在同一文件下的其它程序集
|
||||
//Assembly asembly = Assembly.LoadFrom("包含程序集清单的文件的名称或路径");
|
||||
//Assembly asembly3 = Assembly.LoadFile("要加载的文件的完全限定路径");
|
||||
|
||||
//1.先加载一个指定程序集
|
||||
Assembly asembly = Assembly.LoadFrom(@"D:\VisualStudio2022\VisualStudio Programe\C#\C#进阶\Lesson18_多线程练习\bin\Debug\net8.0\Lesson18_多线程练习.dll");
|
||||
|
||||
#region 如果不知道程序集载入的对不对可以用这个方法看一下
|
||||
Type[] types = asembly.GetTypes();
|
||||
foreach (Type item in types)
|
||||
{
|
||||
Console.WriteLine(item.FullName);
|
||||
}
|
||||
#endregion
|
||||
|
||||
//2.再加载程序集中的一个类对象 之后才能使用反射
|
||||
Type snake = asembly.GetType("Lesson18_多线程练习.Snake");
|
||||
|
||||
#region 如果不知道有什么成员可以用这个方法看一下
|
||||
MemberInfo[] members = snake.GetMembers();
|
||||
for (int i = 0; i < members.Length; i++)
|
||||
{
|
||||
Console.WriteLine(members[i]);
|
||||
}
|
||||
#endregion
|
||||
|
||||
//通过反射 实例化一个 Snake对象
|
||||
//先把枚举也传过来,来得到可传入的参数
|
||||
Type moveDir = asembly.GetType("Lesson18_多线程练习.E_Direction");
|
||||
FieldInfo right = moveDir.GetField("Right");
|
||||
//再实例化Snake对象
|
||||
Object snakeObj = Activator.CreateInstance(snake, 10 ,5 , right.GetValue(null));
|
||||
|
||||
//通过反射调用Snake对象的方法
|
||||
MethodInfo move = snake.GetMethod("Move");
|
||||
MethodInfo draw = snake.GetMethod("Draw");
|
||||
MethodInfo clean = snake.GetMethod("Clean");
|
||||
Console.Clear();
|
||||
while (true)
|
||||
{
|
||||
Thread.Sleep(400);
|
||||
clean.Invoke(snakeObj, null);
|
||||
move.Invoke(snakeObj, null);
|
||||
draw.Invoke(snakeObj, null);
|
||||
}
|
||||
|
||||
//3.类库工程的创建
|
||||
//在Visual Studio中新建一个项目 选择 类库工程
|
||||
#endregion
|
||||
|
||||
#region Activator类
|
||||
//用于快速实例化对象的类
|
||||
//用于将Type对象快速转换为实例对象
|
||||
//先得到Type 然后快速实例化对象
|
||||
Type testType = typeof(Test);
|
||||
//1.无参构造
|
||||
Test testObj = Activator.CreateInstance(testType) as Test;
|
||||
Console.WriteLine(testObj.str);
|
||||
//2.有参构造
|
||||
Test testObj2 = Activator.CreateInstance(testType, 99) as Test;//一个参数的有参构造函数
|
||||
Console.WriteLine(testObj2.j);
|
||||
Test testObj3 = Activator.CreateInstance(testType, 99, "111222") as Test;//两个个参数的有参构造函数
|
||||
Console.WriteLine(testObj3.str);
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
//总结
|
||||
//反射
|
||||
//在程序运行时,通过反射可以得到其他程序集或者自己的程序集代码的各种信息
|
||||
//类、函数、变量、对象等等,实例化他们,执行他们,操作他们
|
||||
|
||||
//关键类
|
||||
//Type
|
||||
//Assembly
|
||||
//Activator
|
||||
|
||||
//对于我们的意义
|
||||
//在初中级阶段 基本不会使用反射
|
||||
//所以目前对于大家来说,了解反射可以做什么就行
|
||||
//很长时间内都不会用到反射相关知识点
|
||||
|
||||
//为什么要学反射
|
||||
//为了之后学习Unity引擎的基本工作原理做铺垫
|
||||
//Unity引起的基本工作机制 就是建立在反射的基础上
|
||||
Reference in New Issue
Block a user